Error reference

Every STACK error is a StackError with a stable machine code, an HTTP status, and a human message. The code is the contract - build retry and branching logic against code, notmessage.

Response shape

json
{
  "error": {
    "message": "Passport has been revoked",
    "code": "PASSPORT_REVOKED",
    "details": { /* optional, varies by error */ }
  }
}

Catalog

Full table. Quick-scan view for lookup; rows you're likely to hit in integration code have their own section below.

text
code                           HTTP  fires when

UNAUTHORIZED                   401   auth missing or invalid
INVALID_API_KEY                401   API key does not hash to a live member or operator
PASSPORT_EXPIRED               401   passport exp has passed (outside the refresh grace window)
PASSPORT_REVOKED               401   passport marked revoked in DB or Redis
FORBIDDEN                      403   generic permission denial (service not in scope, role insufficient, …)
PASSPORT_BLOCKED               403   agent.passport_blocked=true from a prior review decision
TIER_LIMIT_EXCEEDED            403   resource count hit the tier cap (agents, services, members, skills)
TRUST_LEVEL_INSUFFICIENT       403   skill requires identity level the caller has not satisfied
UNAUTHORIZED_SKILL_ACCESS      403   agent's skill_access_mode disallows this skill
IDENTITY_REQUIREMENTS_NOT_MET  403   service has identity requirements the passport does not meet
DELEGATION_DEPTH_EXCEEDED      400   delegation would exceed the 4-hop cap
SCOPE_ESCALATION               400   child passport requests scopes outside the parent's set
ACCOUNTABILITY_REQUIRED        400   enforced or logged agent attempted issue without intent
DELEGATION_ACCOUNTABILITY_VIOLATION 400  delegation would reduce accountability_mode
SCHEMA_VALIDATION_FAILED       400   drop-off deposit failed JSON Schema validation
INVALID_REQUEST                400   zod parse failure on request body or query
INSUFFICIENT_CREDITS           402   wallet empty on a debit path
NOT_FOUND                      404   resource not found (or not owned by the authenticated operator)
SKILL_NOT_FOUND                404   skill id unknown
INVOCATION_NOT_FOUND           404   invocation id unknown
CHECKPOINT_NOT_AVAILABLE       404   checkpoint submitted on a standard-mode passport
CONFLICT                       409   duplicate resource (e.g. agent name collision)
DROPOFF_ALREADY_COLLECTED      409   collect on a drop-off that has already been consumed
DROPOFF_EXPIRED                410   drop-off TTL elapsed before collect
INVOCATION_EXPIRED             410   skill invocation TTL elapsed before completion

The table is exhaustive for user-visible errors. Infrastructure failures (database, Redis, upstream provider) are mapped to a generic 500 with message-only body and should be treated as retryable.

PASSPORT_REVOKED

HTTP 401. The passport was marked revoked in the database; every subsequent proxy or verify call for this jti throws. Revocation is authoritative - do not retry with the same token.

  • Issue a fresh passport with stack_issue_passport
  • If you lost track of the session, issue from scratch - do not refresh a revoked passport
  • If revocation was unexpected, check the security-events feed for the reason

SCOPE_ESCALATION

HTTP 400. On delegation, the child passport asked for a scope the parent does not hold. Child scope must be a subset of parent scope, and child constraints must be a superset of parent constraints (every parent rule rides through).

  • Narrow the child scope array to entries that exist in the parent
  • Do not drop parent constraints when specifying child constraints - concatenate, do not replace
  • Verify the parent's constraints with stack_verify_passport before delegating

DELEGATION_DEPTH_EXCEEDED

HTTP 400. The parent passport is already at the maximum depth (4). A root passport is depth 0; each delegation adds one. Chains of four hops work (0 → 1 → 2 → 3 → 4); attempts to delegate from a depth-4 parent are rejected.

  • Re-issue fresh from the operator rather than extending the chain
  • If this fires at unexpected points, inspect parentClaims.stk.delegation_depth via verify

INSUFFICIENT_CREDITS

HTTP 402. The operation requires a wallet debit but the balance is zero or below the needed amount. Common triggers: sealed-skill invocation, identity verification, proxy call overage after the tier cap.

  • Top up with POST /v1/billing/topup
  • For recurring overage, consider upgrading the tier; see /docs/api/billing
  • A single failed call does not consume credits; retry after top-up is safe

SCHEMA_VALIDATION_FAILED

HTTP 400. A drop-off deposit failed validation against the schema declared at create time. The details object contains the JSON Schema error path and the offending value.

  • Re-check the depositor's payload against the declared schema
  • Schema is locked at create - redeploy a new drop-off with an updated schema if the contract changed

TRUST_LEVEL_INSUFFICIENT

HTTP 403. The invoker does not satisfy the skill's required identity level. Thedetails object names the required level (L1 or L2) and which dimension failed (humanity, identity).

  • Complete the missing verification via POST /v1/identity/verify/initiate
  • Check existing claims with GET /v1/identity/claims - older claims may have expired
  • stack_check_trust_level returns upgrade guidance for the caller

TIER_LIMIT_EXCEEDED

HTTP 403. A count-based resource hit the tier cap. Unlike overage (which opens a wallet-billed path), count caps block until you upgrade or free existing slots.

  • Free a slot (delete an unused agent, revoke an unused service, etc.)
  • Upgrade: POST /v1/billing/subscribe
  • Caps are listed in /docs/api/billing

PASSPORT_BLOCKED

HTTP 403. The agent was blocked from passport issuance by a prior review decision. Every subsequent stack_issue_passport call for this agent throws.

  • Unblock via POST /v1/agents/:id/unblock (operator only)
  • The audit row for the block carries the checkout_id and flag list that triggered it
stack | docs