Skip to content

409 PessimisticConcurrencyConflict ("operation in progress") is treated as a hard failure instead of being retried #252

Closed

Description

Command that triggered the bug

apiops publish

Expected behavior

When APIM returns 409 PessimisticConcurrencyConflict ("Operation on the API is in progress") for a request against an API that has an async operation still settling, the CLI should treat it as a transient condition and retry with backoff. The conflict clears once APIM releases the API lock.

Actual behavior

Publishing an API that has revisions fails with:

ERROR NOOP api/: HTTP 409: {"error":{"code":"PessimisticConcurrencyConflict","message":"Operation on the API is in progress","details":null}}

Mechanism: publishApi publishes the root API (spec import) first, then publishes each revision sequentially (src/services/api-publisher.ts → publishApiRevisions → publishResource in a loop). The root import's async operation reports succeeded, so the CLI immediately issues the next operation on the same API (the first revision). APIM has not yet released the API-level lock from the just-completed import, so it returns 409 PessimisticConcurrencyConflict. There is no settle-wait between the root import completing and the next same-API call.

The retry logic then rejects it, because 4xx responses are deliberately not retried:
src/clients/apim-client.ts — "Do not retry client errors (4xx) — they are deterministic, not transient."
This is correct in general, but 409 PessimisticConcurrencyConflict / "operation in progress" is transient, not deterministic.

apiops CLI version

1.0.0

Environment details

Windows self-hosted agent; Node v24.15.0 / npm 11.12.1; Windows PowerShell 5.1; APIM SKU Developer.

CI/CD environment

Azure DevOps

Is this bug blocking you?

Yes

Activity

  1. github-actions commented on Aug 31, 2026

    @github-actions

    🏷️ Triage Recommendation

    Type: type:bug
    Effort: M — requires targeted fix in apim-client.ts retry logic to carve out PessimisticConcurrencyConflict as a retryable 409, plus possible settle-wait between root API import and revision publishes in api-publisher.ts. Well-scoped but needs careful backoff tuning and testing.
    Domain: src/clients/apim-client.ts (retry policy) · src/services/api-publisher.ts (publish sequencing)
    Confidence: high (90%)
    Uncertainty: none — clear bug report with root cause analysis, reproduction path, and exact file locations identified by the reporter.

    Reasoning

    The retry policy in apim-client.ts explicitly skips all 4xx responses as "deterministic," but 409 PessimisticConcurrencyConflict / "operation in progress" is a well-known transient APIM lock condition, not a client error. The fix is to exempt this specific error code from the 4xx-no-retry rule and apply exponential backoff, and optionally add a settle-wait between the root API import success and the first revision publish.

    Recommended next steps

    • Confirm whether a settle-wait after root import (before revisions) is preferable to retry-on-409, or if both should be applied.
    • Decide max retry count and backoff parameters for this specific error code.
    • Add an integration test or unit test covering the retry path for PessimisticConcurrencyConflict.

    Generated by Contract test: verify context separation for #252 · 16.1 AIC · ⌖ 6.07 AIC · ⊞ 6.5K · ◷

  2. linked a pull request that will close this issueRetry APIM pessimistic concurrency conflicts #255on Aug 31, 2026
  3. added a commit that references this issue on Aug 31, 2026
    b0af0ef
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 releaseeffort:MMedium effort (1-3 days)type:bugSomething broken

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions