API reference
Errors
The error envelope and machine-readable error codes.
Every non-2xx response carries the same JSON envelope:
{
"error": "session is not live",
"code": "session_not_live"
}error— a human-readable message. Don't match on its text; it can be reworded.code— a stable, machine-readable string. Branch on this instead. New codes can appear over time — treat one you don't recognize as a generic failure of the class implied by the HTTP status, not as an error in itself.
Codes
Prefer the primary code when present. "Also seen as" columns are older, equivalent strings that still appear on some paths for historical reasons — treat every column as valid for client branching.
| Code | Also seen as | HTTP | Retryable | Meaning and corrective action |
|---|---|---|---|---|
validation | bad_request | 400 | No | Malformed or invalid request — fix the request body/params, don't retry unmodified. |
payload_too_large | 400 | No | Request content exceeds a transport limit. Deterministic in the content — retrying identically fails identically; shrink the payload instead. | |
unauthenticated | unauthorized | 401 | No | Missing, invalid, or expired credential — refresh it, then retry. |
payment_required | 402 | No | Prepaid balance exhausted, a spend cap was reached, or the balance check was explicitly rejected — top up or raise the cap, then retry. | |
forbidden | 403 | No | Valid credential, not allowed to do this — suspended account, reserved name, or cross-tenant access. | |
not_found | 404 | No | Missing, or missing for this caller. Cross-tenant lookups deliberately look identical to a genuine miss. | |
method_not_allowed | 405 | No | Wrong HTTP method for this path. A well-behaved client should never construct this request — check the API reference rather than retrying. | |
conflict | 409 | No | Well-formed request, current resource state refuses it — re-read the resource's state before retrying. | |
session_not_live | 409 | Yes | A live-only operation (exec, files, fork, ...) against a session that's paused, ending, or not yet ready. Refetch session state and retry once it transitions. | |
org_has_other_members | 409 | No | Account closure was refused because the organisation still has members besides the requesting owner. Remove the other members, then request closure again. | |
no_restore_point | 409 | No | A POST /v1/sessions/{id}/recover was refused because the session has no completed cold snapshot in object storage, or the storage object was missing — do not retry without a usable snapshot. | |
idempotency_key_in_progress | 409 | Yes | A POST /v1/sessions with this Idempotency-Key is already being processed by another request for the same key + customer — retry shortly and it resolves to the same session once that request finishes. Respect the Retry-After header. | |
session_ended | 410 | No | The session has definitively ended past recall — start a new one. When the cause is a session past its own max_lifetime_ms, GET /v1/sessions/{id} reports this ahead of time via state: "lifetime_expired" instead of only surfacing it once a resume attempt fails. | |
session_node_lost | 410 | No | The session's home node was declared permanently dead. Call POST /v1/sessions/{id}/recover to bring it back under the same id from its last cold snapshot, if one survives — GET reports whether it does. Otherwise recreate the session from its template, or restore from your last checkpoint; work since that snapshot is gone. GET still reports the state, DELETE still destroys the session, and POST .../recover attempts recovery — every other operation returns this code. | |
rate_limited | concurrency_limit_exceeded, rate_limit_exceeded | 429 | Yes | Rate or concurrency limit exceeded — back off and retry. Respect a Retry-After header if the response includes one. |
account_concurrency_exceeded | 429 | Yes | The caller's account is already at its concurrent live-session ceiling — back off and retry. Respect the Retry-After header. | |
key_concurrency_exceeded | 429 | Yes | The caller's API key is already at its concurrent live-session ceiling — back off and retry. Respect the Retry-After header. | |
bad_gateway | 502 | Yes | Upstream node unreachable or failing — retry with backoff; the router may resolve it on the next attempt. | |
session_unavailable | 503 | Yes | The session is live but its VM is wedged or unreachable — retry. | |
session_node_unavailable | 503 | Yes | The session's home node is unreachable — retry; the response usually sets Retry-After. | |
template_version_unavailable | 502/503 | Yes | A pinned template version could not be materialized on this node — retry. Never silently falls back to a different cached version of the same template. | |
archive_unavailable | 503 | No | No working cold tier available to durably pause this session to. Needs a node/placement configuration change — retrying the identical pause will not succeed; the session itself was left running untouched. | |
size_unavailable | 503 | No | The requested size cannot fit on any node in the fleet today. Pick a smaller size instead of retrying. | |
node_disk_pressure | 503 | Yes | The node is too full to take this work right now — a create, fork, restore, one-shot run, resume or cold adopt refused by its disk gate. Back off and retry; respect the Retry-After header. A refused wake also raises a session.wake_refused event on the org event stream (and a refused create, session.create_refused), so a tenant that was not the caller still hears about it. | |
unavailable | service_unavailable | 502/503 | Yes | A dependency is temporarily unreachable — retry. |
internal | internal_error | 500 | No | Unexpected server-side failure. The message is intentionally generic; if it persists, share the request ID with support. |
error | any | No | Fallback used only when no more specific code applies. |
The console dual-maps several of these. SDKs surface the code string from the envelope — branch on it, not on error text.