Skip to content

publish aborts the whole gateway/product API association when one referenced API is missing #264

Description

Command that triggered the bug

apiops publish

Expected behavior

Summary

When publishing a Gateway→API (or Product→API/Group) association, publishAssociation
throws on the first link whose referenced API/group does not exist on the target,
which aborts the whole association loop. As a result, APIs that are present on the
target never get linked to the gateway/product — a single missing reference silently
drops all remaining valid associations.

Affected component

  • Repository: Azure/apiops-cli (main)
  • File: src/services/resource-publisher.ts
  • Function: publishAssociation (used for ProductApi, ProductGroup, GatewayApi)

Root cause

The per-entry catch only tolerates the "link already exists" (HTTP 409) case; any other
error — including APIM's HTTP 400 ValidationError … "API not found" / "Group not found"
— is re-thrown, which exits the for loop and marks the whole association failed:

for (const entry of entries) {
  // ...
  try {
    await client.putResource(context, assocDescriptor, {}); // PUT gateways/{gw}/apis/{api}
  } catch (error) {
    // 409 means the link already exists — desired state is in place.
    if (!isLinkAlreadyExistsError(error)) {
      throw error; // ← a single missing API aborts the remaining links
    }
  }
}

The apis.json for a gateway lists every API the source gateway serves. If the publish
scope does not include all of them (e.g. an extraction filter, or an API that failed to
publish earlier in the same run), the association PUT for the missing API returns
API not found, and the loop aborts before linking the APIs that do exist.

Note the inconsistency: Product associations already log a warning and continue on a
missing API/group, while Gateway associations (and product associations that flow
through publishAssociation) abort. The behavior should be consistent.

Steps to reproduce

  1. Have a self-hosted (or workspace) gateway on the source with several APIs assigned.
  2. Extract with a filter that includes the gateway but only a subset of those APIs
    (so gateways/{gw}/apis.json lists APIs that are not in the artifact set).
  3. Publish to a target.
  4. Observe the gateway association fails entirely.

Expected behavior

  • Links for APIs/groups that exist on the target are created.
  • A missing referenced API/group is skipped with a warning and does not abort the
    remaining links.

Actual behavior

Actual behavior

ERROR NOOP gatewayapi/<gateway>: HTTP 400: {"error":{"code":"ValidationError",
"details":[{"target":"aid","message":"API not found"}]}}

No APIs are linked to the gateway — including the ones that were published successfully.
The API ends up served only by the managed gateway (which is implicit), so it looks like
"only one gateway survived."

Downstream impact

  • Self-hosted / workspace gateway assignments silently disappear on publish whenever the
    gateway's apis.json references any API outside the current publish scope.
  • Cascades: SOAP or other APIs that fail to import earlier in the run also cause every
    gateway link to be dropped, not just their own.

Suggested fix

Treat a missing referenced API/group as a per-entry skip (warning) instead of a fatal
error, mirroring the existing "link already exists" handling and the product-association
behavior:

} catch (error) {
  if (isLinkAlreadyExistsError(error)) {
    continue;
  }
  const message = error instanceof Error ? error.message : String(error);
  if (message.includes('API not found') || message.includes('Group not found')) {
    logger.warn(
      `Skipping ${associationType} association '${entry.name}' on ` +
      `'${getNamePart(descriptor.nameParts, 0)}': referenced resource not found on target`
    );
    continue;
  }
  throw error;
}

apiops CLI version

1.0.0

Environment details

  • VSCode - Devcontainer
  • Azure/apiops-cli main
  • Command: publish

CI/CD environment

None

Is this bug blocking you?

Yes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

close:fixedFixed by a previous PR or releasetype:bugSomething broken

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions