Error reference
Stable platform error codes and practical recovery steps.
Identify the error source
Read X-System-One-Error-Source and X-System-One-Error-Code before interpreting a status. upstream means a valid provider JSON error is forwarded with its original 400–599 status and body. It may contain a detail array, a string, or a provider-specific error object; it need not use the platform envelope. For example, a forwarded validation body can look like this:
{
"detail": [
{ "loc": ["body", "questions"], "msg": "Invalid question definition", "type": "value_error" }
]
}This is an illustrative error, not a production failure. The gateway preserves a supplied Retry-After as seconds or an HTTP date. Upstream 401/403 remain 401/403, 400/422 remain 400/422, and 429/529 remain 429/529. A provider authentication error is not evidence that your browser session expired. Even platform errors with a provider_* code can describe a sanitized upstream authentication failure; do not redirect those users to sign in.
The stable classification header is provider_busy for upstream 429/529, provider_rejected_request for 400/422, and provider_unavailable for other upstream HTTP failures. The original body may have an unrelated code. Render a localized message from the header classification, not upstream message or detail text. Error bodies may echo input and should not be logged indiscriminately.
Platform error envelope
X-System-One-Error-Source: platform identifies local errors and safe replacements. Local System One errors use the following envelope; payment-provider routes retain TinyShip's payment contract. Values below are illustrative:
{
"error": {
"code": "insufficient_credits",
"message": "This request requires 3 credits. Top up your account to continue.",
"request_id": "example-request-id"
},
"request_id": "example-request-id"
}Use the header code first; the platform envelope also contains error.code. Read the platform ledger ID from X-Request-Id and the optional upstream ID from X-Upstream-Request-Id. A provider's body request_id is not a platform identifier. Do not record authorization headers or sensitive request content in error logs.
The project SDK @system-one-ai/sdk@0.3.0 uses a separate error namespace: its APIError retains status, request ID and retry delay but deliberately drops the server body. Use raw Fetch headers for the platform classification. The official @typesafe-ai/sdk@0.6.0 has its own error classes; do not assume the two clients expose the same shape or safely log either error object wholesale.
Authentication and input
| HTTP | Code | Meaning and next step |
|---|---|---|
| 400 | invalid_json | Missing/malformed/invalid-UTF-8 JSON or duplicate object keys, including escaped names. Correct the request body. |
| 401 | invalid_api_key | Missing, invalid, or revoked Bearer key. Use a valid platform key. |
| 401 | unauthorized | A valid account/session is required for this endpoint. Sign in. |
| 403 | account_disabled | The account is disabled. Contact the deployment operator. |
| 403 | invalid_origin | A browser mutation did not originate from the configured app origin. |
| 404 | not_found | The endpoint does not exist. Check the main application base URL and path. |
| 404 | key_not_found | The key does not exist or does not belong to your account. |
| 405 | method_not_allowed | Use the HTTP method documented for this endpoint. |
| 413 | request_too_large | Raw request body exceeds 65,536 bytes. Reduce the state or questions. |
| 415 | unsupported_media_type | Send Content-Type: application/json. |
| 422 | invalid_request | A field, question, name, count, or nesting depth is invalid. |
| 422 | invalid_idempotency_key | Use the allowed idempotency key format. |
Authentication and local admission validation failures occur before a new inference reservation and do not charge decision credits. An upstream rejection after reservation is refunded. Existing operations are unaffected.
Credits, concurrency, and limits
| HTTP | Code | Meaning and next step |
|---|---|---|
| 402 | insufficient_credits | The balance cannot cover this request. Top up or reduce the request. |
| 409 | key_limit_exceeded | There are already 20 active API keys. Revoke an unused key. |
| 409 | idempotency_conflict | The same account used this key with another canonical body. |
| 409 | request_in_progress | The original request is pending. Respect Retry-After, then use the same key/body. |
| 409 | idempotency_failed | The original operation failed and was refunded. A new attempt needs a new key. |
| 409 | request_expired | The reservation was already terminated and refunded before completion. |
| 410 | idempotency_expired | The retained record no longer contains replay data. Reconcile before another operation. |
| 429 | rate_limit_exceeded | Wait for Retry-After; the default decision limit is 120 per account per minute. |
An expired key may already have been removed rather than returning 410. After the 24-hour window, do not rely on it to deduplicate a new request.
Provider and infrastructure
| HTTP | Code | Meaning and next step |
|---|---|---|
| 503 | provider_not_configured | No usable provider credentials or URL are configured. No new credits were reserved. |
| 503 | app_not_configured | The browser app origin is not configured correctly. Ask the operator to fix APP_BASE_URL. |
| 429 / 529 | provider_busy | Original upstream status; reserved credits are refunded. Observe the original Retry-After. |
| 400 / 422 | provider_rejected_request | Original upstream status; correct the request after the recorded refund. |
| Other upstream 4xx / 5xx | provider_unavailable | Original status, including upstream 401/403 and 500. Check the error source and contact the operator as needed. |
| 502 | invalid_provider_response | Invalid/unsafe upstream success, malformed JSON or UTF-8, response over 1 MiB, or a redirect. No default answer is generated. |
| 503 | provider_configuration_error | The explicit adapter configuration needs attention. |
| 502 | provider_unavailable | Transport failure before a usable upstream response. |
| 504 | provider_timeout | The 20-second upstream headers-and-body deadline expired. |
| 499 | request_cancelled | The caller cancelled the request. |
| 501 | model_listing_not_supported | The selected OpenRouter provider does not offer this native TypeSafe model-list endpoint. |
| 503 | request_reconciliation_pending | Immediate refund reconciliation failed. The charge header is omitted; keep the request ID and check the original operation. |
| 500 | internal_error | An unexpected service failure occurred. Keep the request ID and reconcile before starting another operation. |
The gateway refunds a decision reservation before returning an ordinary upstream error. X-System-One-Credits: 0 confirms no retained charge for that attempt; absence of the header is not zero. If immediate refund reconciliation fails, 503 request_reconciliation_pending takes precedence and the charge header is omitted. Model-list requests never reserve decision credits.
Safety exceptions and retry recovery
An upstream error containing the exact operator credential, including a JSON-escaped representation decoded to that credential, receives a safe platform body while retaining the upstream status. Its source becomes platform, its stable provider classification remains available, and no provider error text is shown in the UI. A credential-bearing success is rejected with 502. Malformed/non-JSON/invalid-UTF-8 bodies, oversized responses and redirects are also rejected with 502 invalid_provider_response; redirects are never followed.
Only documented safe tracking/rate headers, Content-Type and Retry-After are forwarded; secret-bearing header values are omitted. Cookies, authorization and Location are not forwarded. These explicit exceptions mean the gateway does not promise unconditional byte forwarding of every response.
For a recorded provider failure, reusing its key returns idempotency_failed. A new key is appropriate only after the failed/refunded outcome is known. A transport timeout in your client is not proof that the server failed: first recover with the existing key. The Worker performs no automatic upstream retries; SDK retry settings are separate.
See idempotency for crash recovery, legacy-cache and the 24-hour window; see deployment for operator configuration.