Search

↑↓ to move↵ to openesc to closetop 6 documentation results

Book a demoTry TokenTriage

In development · Explore the product preview. Join the launch list or book a walkthrough.

Browse docs

Errors & problem+json

The Management API error contract — RFC 9457 problem+json with a registered type, a stable code, and a request_id.

Reference

On this page

Every non-2xx from the Management API is application/problem+json (RFC 9457) with a registered type, a stable machine-readable code, and a request_id that matches the TT-Request-Id header carried on every response.

For symptom-first fixes keyed to what you’d actually search — 401 storms, UNPRICED rows, silent routing — see Troubleshooting.

The envelope

  • type — a relative on-host path (air-gap-dereferenceable), documented at /tt/api/problems/<slug>; the full registry is served at /tt/api/v1/problems.
  • code — a stable string code.
  • request_id — matches the TT-Request-Id response header, for correlation with the ledger and the audit trail.

Framework problems

These apply to every operation and are documented once (they’re each operation’s default response):

Status Problem
400 bad_request
401 unauthenticated
403 forbidden (names the required_scope in the body and the TT-Required-Scope header)
404 not_found
405 method_not_allowed
413 payload_too_large
429 rate_limited (with Retry-After)
500 internal

Special status codes worth knowing

  • 412 precondition_failed — a config compare-and-swap lost the race; refetch the generation and retry (If-Match).
  • 422 restart_required — a restart-only config change (e.g. a webhooks: edit) was submitted; nothing was written (previews still return 200). Also 422 unsupported_override_class when overriding a rate/concurrency limit per node.
  • 410 gone — a sunset operation (names its successor), or 410 cursor_expired on the events feed (carries oldest_seq so you can reconcile from the audit trail).
  • 503 enforcement_unavailable — a fail: closed governance limit whose guarantee is uncheckable (never a fake 429; see Governance).

Guardrail boot refusals

These are not HTTP statuses. A malformed guardrail policy refuses at boot — the process does not start — so that no row is ever written carrying a fallback disclosure for a policy that should not exist. The three you are most likely to meet:

What you wrote The refusal
A phase a detector does not declare binding "code_out" binds detector "code.patterns" to phase "stream", which it does not declare (declared: [output])
on_error: closed with no ack binding "pii_in": on_error 'closed' requires fail_closed_ack — a dead detector becoming an outage is a decision an operator must type out
A judge or sidecar detector with no consent guardrails.judge.external: … It requires external: allow — the air-gap gate. Without it this tier is REFUSED

Also refused: mode: simulate in a binding (it is the dry-run report’s stamp, never a policy), and stream_fallback: closed without the same fail_closed_ack. Stock activation also rejects empty detector lists, rewrite, reask, stream_fallback: buffer, sidecar bindings, raw-required external detectors and spanless mutation combinations. Positive judge hard caps require a proven conservative reservation price; an explicit zero cap denies every call. See Configuring a guard.

Governance refusal reasons

Governance refusals map a reason to a status: invalid_key → 401, scope_violation → 403, budget_exceeded / quota_exhausted / rate_limited / concurrency_exceeded → 429, enforcement_unavailable → 503. Each is written row == wire — the HTTP response and the decision-log row are stamped from the same value.

The full catalog, and the type registry, are in the rendered API reference.