Skip to content

Policy Lock Timeout

URI: https://docs.ankatech.co/errors/policy-lock-timeout
HTTP Status: 503 Service Unavailable

When you see this

A policy write needed the active deployment policy row and could not take its lock within the bounded wait, because a concurrent deployment policy write was still holding it. Nothing was changed.

Every tenant policy write is validated against the deployment policy as a ceiling, so it reads the deployment row under a shared lock and waits for an in-flight deployment write to commit before comparing against the committed row. A deployment policy write takes the row exclusively. Both waits are bounded by a statement timeout of five seconds; when it expires, the write has done nothing and the request is answered with this status.

503 and not 500: nothing is wrong with the request and nothing is defective — the same body a moment later succeeds. A 500 would send an operator looking for a defect that does not exist.

Common Causes

  • A deployment policy PUT, reset, or bulk PUT was in flight and held the deployment policy row for longer than the five-second wait — for example, an algorithm policy change whose cross-tenant cascade check had many tenants to compare.
  • Two deployment policy writes arriving close together; the second waits for the first.
  • A tenant policy write, reset, override-flag toggle, hydration, or tenant provisioning that landed while a deployment write was committing.
  • An unusually slow deployment write holding the row — for example one contending on a busy database.

Response Example

HTTP/1.1 503 Service Unavailable
Content-Type: application/problem+json
Retry-After: 5
{
  "type": "https://docs.ankatech.co/errors/policy-lock-timeout",
  "title": "Policy Lock Timeout",
  "status": 503,
  "detail": "The deployment policy is being changed by another operation and the lock could not be acquired within the allowed time. Nothing was changed; retry the operation shortly.",
  "instance": "/api/v3/admin/tenants/3f9a1b62-5d47-4c8e-b0a2-91d7e4f60cc5/policies/algorithm-availability",
  "timestamp": 1730000000,
  "extensions": {
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
}

Content-Type: application/problem+json — the response follows RFC 9457 Problem Details.

The detail is a fixed string: it names no row identifier, no SQL, and no lock holder. The underlying cause is retained for server-side logging only.

How to Resolve

  1. Wait the number of seconds in the Retry-After header (5) and retry the same request. Nothing was written, so the retry is safe and is the intended response.
  2. If an automation issues deployment and tenant policy writes concurrently, serialise them client-side: apply the deployment policy first, then the tenant policies.
  3. If it persists, investigate what is holding the deployment policy row open for longer than the wait bound — persistent occurrences point at a slow deployment write, not at contention.

Operations that emit it

Every handler that reads the deployment policy row under the bounded lock declares this response:

Method Endpoint Lock taken
PUT /api/v3/admin/platform/deployment/policies exclusive (algorithm write, then rotation write)
PUT /api/v3/admin/platform/deployment/policies/algorithm-availability exclusive
PUT /api/v3/admin/platform/deployment/policies/rotation exclusive
POST /api/v3/admin/platform/deployment/policies/algorithm-availability/reset exclusive; the active row is updated in place, never deactivated and re-inserted
POST /api/v3/admin/platform/deployment/policies/rotation/reset exclusive; the active row is updated in place, never deactivated and re-inserted
POST /api/v3/admin/platform/deployment/policies/algorithm-availability/hydrate-all-tenants shared, once per tenant row created
POST /api/v3/admin/platform/tenants/provision shared, for the initial policy set
PUT /api/v3/admin/tenants/{tenantId}/policies/algorithm-availability shared
DELETE /api/v3/admin/tenants/{tenantId}/policies/algorithm-availability shared
PUT /api/v3/admin/tenants/{tenantId}/policies/rotation shared
DELETE /api/v3/admin/tenants/{tenantId}/policies/rotation shared
PATCH /api/v3/admin/tenants/{tenantId}/policies/override-flag shared, only when a missing row is created

The deployment lifecycle policy has its own write path and does not take this lock.

For full schema definitions, examples, and interactive testing, see the Developer Hub Reference.