Errors, Response Envelopes & Status Codes
Every surface of the Alien Intelligence platform returns errors in a predictable shape. This page collects the conventions in one place: the REST envelope returned by the Platform API, the HTTP status codes and what each means on this platform, how streaming endpoints surface failures, the GraphQL error shape, and a short guide to handling errors robustly.
The REST Envelope
The Platform API wraps every JSON response — success or failure — in a consistent envelope. Clients can branch on the boolean success field before reading any payload.
Success
A successful response carries success: true and the result under data:
{
"success": true,
"data": { ... }
}
List endpoints add a meta block with pagination:
{
"success": true,
"meta": {
"currentPage": 1,
"total": 42,
"perPage": 100,
"lastPage": 1
},
"data": [ ... ]
}
Error
A failed response carries success: false, a human-readable top-level message, and an error object that always contains the numeric HTTP status:
{
"success": false,
"message": "Resource not found",
"error": {
"status": 404
}
}
The published ErrorResponse schema documents exactly three fields — success (always false), message (a string), and error.status (an integer). At runtime the platform may attach additional diagnostic fields to the error object (such as a short error name and a data payload), but only success, message, and error.status are part of the stable contract — treat anything else as best-effort detail.
Branch on success, not on the HTTP status alone. The envelope is the source of truth; error.status mirrors the HTTP status code so you can read it even where the transport status is awkward to access.
Validation errors
When a request fails schema validation, the same envelope is returned with status: 422 and a per-field breakdown under error.messages:
{
"success": false,
"message": "Validation failure",
"error": {
"status": 422,
"messages": [
{ "field": "name", "rule": "required", "message": "The name field is required" }
]
}
}
Each entry names the offending field, the rule it violated, and a readable message.
The Data API uses a different error shape
The Data API that runs on each data cluster is a FastAPI service, so it does not use the Platform envelope. Its errors are a flat object with a single detail field:
{
"detail": "Entry with id 999 not found"
}
When you reach the Data API through the Platform's cluster proxy, the proxy forwards the Data API's status code and body transparently — so a proxied call can surface either envelope depending on which layer rejected the request.
The OpenAI-compatible surfaces are not enveloped
The OpenAI-compatible endpoints — the Responses API (POST /agent/{id}/responses), the Chat Completions API (POST /agent/{id}/chat/completions), and the Files API (/v1/files) — return bare, OpenAI-shaped objects, not the platform { success, data } envelope. A successful Files call returns a FileObject / FileList directly; a successful streaming call returns the OpenAI SSE event stream. Do not look for a success field on these surfaces.
Errors are surface-specific, so consumers must branch by surface, not assume the envelope:
- Streaming surfaces (Responses, Chat Completions) report errors in the OpenAI
{ "error": { … } }shape — as a pre-stream HTTP4xx/5xxbody before the first event, or as a terminal in-stream failure event after it (see Streaming Errors). - Files API returns its success bodies OpenAI-shaped, but its error responses (
400/401/404/500) fall back to the platform{ success: false, message, error.status }envelope documented above — so a Files consumer reads OpenAI shapes on the happy path and the platformErrorResponseon failure.
HTTP Status Codes
The platform uses standard HTTP semantics. The table below describes what each status means specifically on this platform.
| Status | Meaning | When you'll see it |
|---|---|---|
| 400 Bad Request | Malformed or invalid request | A missing/invalid parameter, a malformed header (e.g. an invalid MCP config or composite dataset ID), or a payload the endpoint can't parse |
| 401 Unauthorized | Missing or invalid credentials | No Bearer token, an expired/invalid OAuth JWT, or a revoked/unknown API token. The dual-guard tries OAuth then API token; if both fail you get 401 |
| 403 Forbidden | Authenticated, but not allowed | Your organization role or a resource policy denies the action; you lack the required token ability; or the target cluster is suspended. You are known — you just can't do this |
| 404 Not Found | Resource does not exist | The dataset, entry, workflow, job, or other resource ID/slug was not found (or is not visible to you) |
| 409 Conflict | State conflict | A uniqueness or duplicate-resource conflict — e.g. creating an entry with a slug that already exists, or a tool definition that already exists |
| 422 Unprocessable Entity | Validation failure | The request was well-formed but failed schema validation. The error.messages array lists the offending fields (see above) |
| 429 Too Many Requests | Rate limited | Surfaced when a proxied upstream (e.g. a metered external API) rate-limits the call. The platform relays the upstream 429 and any Retry-After header. The Platform API itself does not currently throttle |
| 500 Internal Server Error | Unexpected server fault | An unhandled error on the platform side. Safe to retry with backoff; if it persists, it's a platform-side issue |
| 503 Service Unavailable | Backend temporarily unreachable | The target data cluster is offline (its last heartbeat is stale, or it is being deleted). Reads and writes through the proxy are rejected until it recovers |
Where these are enforced
- 401 / 403 are enforced by the authentication guards and the authorization policy system. The authorization check runs before any database query or external call — so a 403 means the request never touched your data.
- 422 is produced centrally: VineJS validation failures are caught by the global exception handler and serialized into the envelope above.
- 403 vs 503 for clusters is a deliberate distinction. A suspended cluster returns 403 (an authorization decision — the cluster is disabled for policy reasons). An offline cluster returns 503 (an availability problem — the cluster's heartbeat went stale and it may recover). See the cluster proxy authorization for how proxy requests are gated.
Streaming Errors
The streaming endpoints (the Responses API and the Chat Completions API) surface failures differently depending on when the failure happens relative to the first SSE event.
Before the stream starts
If the request is rejected before the first event is sent, you get an ordinary HTTP 4xx/5xx response whose body matches OpenAI's standard error envelope:
{ "error": { "message": "...", "type": "invalid_request_error", "code": "..." } }
After the stream starts
Once events are flowing, the connection has already committed to 200 OK, so a failure cannot change the HTTP status. Instead it arrives as a terminal response.failed event carrying Response.error with a code and message:
{
"type": "response.failed",
"sequence_number": 42,
"response": {
"id": "resp_...",
"status": "failed",
"error": { "code": "server_error", "message": "..." },
"metadata": {
"x_alien_error_code": "upstream_timeout",
"x_alien_error_message": "upstream model timed out after 30s"
}
}
}
Response.error.code is constrained to OpenAI's documented literal codes — server_error, rate_limit_exceeded, invalid_prompt, and so on. Alien-specific failure detail is carried alongside it in metadata.x_alien_error_code / metadata.x_alien_error_message, so a consumer that wants the precise cause should read those.
A notable Alien-specific code is worker_disconnected — the agent worker dropped its connection mid-run (rather than the model itself failing). Clients should treat a terminal failure as retryable: re-issue the turn, optionally reusing the conversation handle, rather than leaving the user with a silently empty response.
SSE heartbeat comment lines (:keep-alive) are emitted during quiet periods and do not parse as events or advance the sequence_number. Don't mistake a quiet stream for a failed one.
See the Responses API errors section for the full event taxonomy and the native sequence_number-based resume that lets a UI recover an in-flight run after a network blip.
GraphQL Errors
The platform exposes a GraphQL surface at POST /graphql for metrics and reporting data (see Querying metrics with GraphQL). GraphQL errors follow the GraphQL specification rather than the REST envelope. The HTTP response is typically 200 OK, and failures are reported in a top-level errors array alongside any partial data:
{
"data": null,
"errors": [
{
"message": "Resource not found",
"path": ["dataset"],
"extensions": { "code": "NOT_FOUND" }
}
]
}
Always check for a non-empty errors array even when data is present — GraphQL can return partial data with per-field errors. Provider-specific codes are conventionally placed under extensions.code.
Handling Errors
A few rules of thumb cover almost every case:
- Branch on the envelope, not the transport. Read
success(REST) or theerrorsarray (GraphQL) before consuming a payload. For streams, watch for the terminalresponse.failedevent even after a200 OK. - Retry
5xxand503, with backoff.500and503are transient — a503in particular means a data cluster is briefly offline and may recover on its own. Use exponential backoff with jitter, and cap the number of attempts. - Honor
429andRetry-After. When a proxied upstream rate-limits you, wait for the interval theRetry-Afterheader specifies before retrying. - Do not retry
4xx(except429).400,401,403,404,409, and422indicate something about the request that won't change on its own — fix the input, the credentials, or the permissions instead. Re-validate againsterror.messagesfor a422. - Surface streaming failures to the user. A mid-stream
response.failed(e.g.worker_disconnected) should produce a visible, retryable error rather than an empty result. Re-issue the turn to recover. - Log
error.statusandmessage. They are stable across the API; the human-readablemessageis for operators, not for parsing — branch on the status code, not on message text.
Next Steps
- Platform API Overview — Authentication, conventions, and the envelope in context
- Data API Overview — The FastAPI service on each data cluster and its
detailerror shape - Responses API — Streaming event taxonomy and native resume
- Security Model — How 401/403 authorization is enforced before any data access