Troubleshoot system and 5xx error codes
The generic system codes —INTERNAL_ERROR, BAD_GATEWAY, UPSTREAM_ERROR,
UNPROCESSABLE_ENTITY, INVARIANT_VIOLATION, MISSING_TENANT, and
TENANT_NOT_FOUND — surface on requests that failed before the caller’s
domain logic could run. They read as opaque platform failures, but most split
into two clear classes: transient (safe to retry) and deterministic
(retrying changes nothing — fix the request or escalate). This page tells you
which class a code belongs to and what to do about it.
Step 1 — read the retry-safety flag on the envelope
Before you classify anything, look at the error envelope you got back. Each response carries anerror object with code, message, status, and
optional details, plus a meta block with request_id and docs_url:
details.retryable: when a transient class of failure is identified before the response is built, the envelope is stamped"retryable": true. That marks the response as designedly safe to retry — the platform has deliberately classified this failure as an availability blip, not a fault.details.retry_after_seconds: when the envelope also names a wait window, the response carries it both indetailsand as a standardRetry-Afterheader. Honour that window before retrying instead of retrying immediately.
meta.request_id — it is the handle
support uses to trace the failure if you escalate.
One well-known transient class,
TENANT_SCHEMA_INCOMPLETE, has its own
runbook at
Troubleshoot TENANT_SCHEMA_INCOMPLETE (503).
Check for that code before treating a 503 as generic.Step 2 — classify the code
The table below lists the system codes as they appear in responses. Thestatus field on a response is always authoritative for that response —
where a code can surface under more than one status, the table names the
value you most commonly see.
UNPROCESSABLE_ENTITY and VALIDATION_ERROR are both 422 determinants —
match on the response code, not the message text. Either way, the fix is in
your payload, not in a retry.Step 3 — the decision checklist
Walk these steps in order on any of the codes above:- Read the envelope. Capture
error.code,error.status, andmeta.request_id. - Status page. For
UPSTREAM_ERRORorBAD_GATEWAY, check status.orbit.devotel.io before you retry or escalate — an active incident answers every question. - Retry or fix. Retry only when the envelope says
retryable: true, or the operation is a read, or it accepts a freshIdempotency-Keyand you supply one. For a deterministic code (UNPROCESSABLE_ENTITY,MISSING_TENANT,TENANT_NOT_FOUND), fix the request and move on. - Escalate. If a retryable check, a payload fix, and one retry all
return the same code, or the code is
INTERNAL_ERRORorINVARIANT_VIOLATION, open a support ticket.
Worked examples
A transient 503 stamped safe by the platform — the designed retryable envelope you should pass straight through your retry loop:meta.request_id:
Escalation
Open a support ticket when any of these holds:- The status page shows no incident, yet
UPSTREAM_ERRORorBAD_GATEWAYpersists past a few minutes of backoff. - The response says
retryable: trueand you have already retried within the stated window, but the same failure returns. - The code is
INVARIANT_VIOLATIONorINTERNAL_ERROR— both name the platform. - The code is
MISSING_TENANT/TENANT_NOT_FOUNDand a working key suddenly stops resolving its organization.
meta.request_id, the payload body (minus any credentials), and
whether the failure is reproducible or intermittent.
See also
- Error code reference — every code the API can return.
- Idempotency and billing gates
— how
Idempotency-Keymakes a retry-safe mutation. - Rate limits — the deliberately transient 429 class.
- Troubleshooting hub — the entry point for every runbook.