Skip to content

Dependency Not Ready

URI: https://docs.ankatech.co/errors/dependency-not-ready
Boot-plane form: /problems/dependency-not-ready
HTTP Status: 503 Service Unavailable

When you see this

A request was refused because a backing dependency it needs is not available. You receive no result you could use, and the same request can be retried after the interval the response names. Whether the operation itself was carried out depends on the cause: most refusals happen before anything is done, but an operation whose audit record could not be confirmed may already have been performed (see below).

The refusal reaches you in one of two forms, distinguished by type:

  • /problems/dependency-not-ready — the platform-wide boot-plane refusal. Every service that registers its backing dependencies answers with it, and it is the form you meet on the data plane.
  • https://docs.ankatech.co/errors/dependency-not-ready — the operator form, returned by the platform projection republish endpoint when Redis is down: there is nothing to publish the projections to, so the request is refused rather than accepted with a re-drive that could not do anything.

The audit trail is one of those dependencies

An operation whose audit record is part of the operation is answered only after that record is confirmed by the event stream. When it cannot be confirmed, the operation is refused with the boot-plane form instead of being answered without its tamper-evident trail.

When the refusal comes from a record that was sent and could not be delivered, the operation had already been performed and only its answer is withheld. The service then signs a second record, the withheld-result outcome, that names the refused record by its event id and carries the same correlation id. The audit trail shows the operation once, with the final state performed, result withheld, and a withheld operation is not billed. A request refused inside the refusal window described below was never attempted and leaves no such record. This applies to:

  • Crypto operations and the key reads on the Core API: the buffered and streaming crypto operations, the PKCS#7 analysis and conversion, the interoperability operations, and listing keys, reading a key's metadata and listing the supported algorithms — every operation of the crypto audit vocabulary except key rotation and key revocation. A buffered operation returns the refusal in place of its result. A streaming operation is refused before the first byte; if the audit of a stream that has already started cannot be confirmed, the response ends without its closing boundary, so a client never receives a complete result whose audit failed. A buffered answer waits on the audit only for a licensed user caller; a streaming answer waits on it for every caller, marketplace included. Either way a request has one audit record: once its success is confirmed, a later failure of the same request adds no second record.
  • Token, logout and token revocation on the Auth API. The refusal is identical whatever the credential outcome would have been, and no access or refresh token is returned or stored. Logout and revocation still revoke the token before answering. A federated (OIDC/SAML) login redirects with identity_provider_unavailable instead.

    Emergency access is the one exception. A break-glass sign-in — a designated member signing in through the emergency-access entry with a security key — is never refused because its audit record could not be confirmed, not even inside the refusal window: its auth.login.breakglass record is written without refusing, the redemption of its code is admitted, and when a record cannot be recorded the session is still issued and an independent SECURITY_EVENT log record (security_event=break_glass.audit_unrecorded, with tenant, user, outcome, failure class and time — never a credential) is written instead, counted as ankasecure.audit.recording.failed{reason=break_glass_unrecorded}. Every other grant — a valid password login, a wrong password, an unknown user, an ordinary authorization code — receives the refusal. - POST /init on the PQC Handshake API. No session key is left behind.

The platform is re-establishing its session store

When the platform's session and revocation store has lost its data (for example after an environment restore), it refuses to issue tokens until the store is re-established, which takes seconds: a token issued in that window would be refused everywhere. During it, every grant of the Auth API token endpoint answers with the boot-plane form before any credential is examined, and a federated (OIDC or SAML) sign-in redirects with identity_provider_unavailable (an LDAP sign-in answers the boot-plane form). Retry after Retry-After. Tokens and refresh tokens issued before the loss are no longer accepted, so sign in again rather than refreshing. - The platform crypto-statistics refresh on the Audit API.

After one refused confirmation the service refuses new audited operations of the same kind for one Retry-After interval before attempting anything, so a retry storm does not reach the broker. The first request after the interval tries again for real.

PQC transport sessions

The PQC transport session store is also one of those dependencies:

  • POST /init on the PQC Handshake API is refused with the boot-plane form when the new session cannot be stored. No session is left behind; retry the whole handshake.
  • A PQC-transport request (X-PQC-Transport: true with X-PQC-Session) to the Core API, the Admin API or the Auth API is refused with the boot-plane form when its session cannot be read. The request was not processed and nothing falls back to unencrypted HTTP; retry it after the interval.

Two consequences are worth knowing before you retry:

  • A stateful signature that was refused after its one-time index was reserved does not reuse that index; the retry signs with the next one.
  • A capped-use key whose use was counted before the refusal keeps that use counted.

Common Causes

  • The event-streaming backbone (Kafka) is down, unreachable, or still starting — the audit cause above.
  • Redis, PostgreSQL or another registered dependency is down, unreachable, or still starting.
  • The session and revocation store lost its data and is being re-established (token issuance only).
  • A network partition between the service and the dependency.
  • Credentials or TLS material for the dependency are wrong, so the connection never establishes.

Response Example

Boot-plane form, as the Core API returns it:

{
  "type": "/problems/dependency-not-ready",
  "title": "Service Dependency Not Ready",
  "status": 503,
  "detail": "A required dependency is temporarily unavailable. Retry after the indicated interval.",
  "instance": "/api/v3/crypto/encrypt",
  "correlationId": "550e8400-e29b-41d4-a716-446655440000"
}

The title and detail are fixed: they never name the dependency, Kafka, the audit trail, a topic or an exception, and the Retry-After header carries the same value for every dependency (30 seconds by default). The correlation member follows the service that answered — top-level correlationId on the Core API and the PQC Handshake API, extensions.requestId on the Audit API, and only the X-Correlation-Id header on the Auth API.

Operator form:

{
  "type": "https://docs.ankatech.co/errors/dependency-not-ready",
  "title": "Service Unavailable",
  "status": 503,
  "detail": "The projection cache is unavailable; the projections cannot be re-driven right now."
}

The operator form builds its body from the framework's problem type directly, so it carries the five RFC-defined members only. It has no timestamp and no extensions block, and instance is not populated.

Content-Type: application/problem+json — both forms follow RFC 9457 Problem Details.

How to Resolve

  1. Retry after the Retry-After interval. The refusal is transient by design.
  2. If it persists, an operator checks the dependency: for the audit cause, Kafka and the answering service's connection to it. Platform Alerts raises Audited operations are being refused while it lasts.
  3. Confirm the service sees the dependency as healthy again — the readiness probe reports the boot dependencies.

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