Chat API
Read this page as MarkdownIn this section: Errors
Errors
Every status the Chat API returns, with its type, code, cause and fix, in the OpenAI error envelope.
The envelope
Every error, including a 413 raised before the body is parsed and an error mid-stream, is JSON in the OpenAI shape:
{"error": {"message": "api key revoked or unknown", "type": "invalid_request_error", "code": "invalid_api_key"}}A 401 also carries WWW-Authenticate: Bearer realm="askmiles", error="invalid_token", so an OAuth-aware SDK's retry logic behaves the same whichever bearer type it sent. A 429 carries Retry-After. Nothing here is cached: every error response is no-store.
The one error that does not wear the envelope is a plain-text 403 from Cloudflare, returned before Miles sees the request when the User-Agent is a stock Python-urllib. Use a client library.
The table
| Status | type | code or message | Cause | Fix |
|---|---|---|---|---|
| 400 | invalid_request_error | request body must be a JSON object | The body was not an object | Send {"model": "miles", "messages": [...]} |
| 400 | invalid_request_error | names the field | A role other than system/user/assistant, an image or audio part, a malformed messages entry | Remove the part; only text content is read |
| 401 | invalid_request_error | invalid_api_key | The key was revoked or never existed, or the OAuth token expired | Mint a new key, or refresh the token |
| 401 | invalid_request_error | invalid_token | The bearer is not a Miles credential, or lacks miles:chat | Send a personal key or a miles:chat token |
| 403 | invalid_request_error | connections_paused | The account paused its AI app connections | The user turns them back on at Settings → Connected AI Apps; nothing to re-mint |
| 413 | invalid_request_error | request too large | The body exceeded the size cap | Trim history; only the last 26 messages are read anyway |
| 429 | rate_limit_exceeded | rate limited, retry after Ns | The per-minute window is full. GET /v1/models has its own such window, separate from the one completions use | Wait Retry-After; safe to retry |
| 429 | rate_limit_exceeded | concurrency limited, retry after 2s | Another turn is running on this grant or on another grant of the same account, or the service is at its shared ceiling | Reduce parallelism, then retry |
| 429 | rate_limit_exceeded | You've reached today's usage limit. Please try again later. | The account's daily spend allowance is full. This is not the per-minute window and does not clear in a minute | Wait Retry-After, which is an hour here; the allowance resets at midnight Pacific |
| 429 | insufficient_quota | You've used this month's budget. It resets on … | The account's monthly budget is spent | Wait Retry-After, which is the seconds until the reset date and can be days, so do not retry on the usual 429 schedule. Members get a much larger monthly budget |
| 500 | server_error | the pipeline failed to answer | Miles could not produce an answer | Retry once; if it repeats, the outage is on Miles' side |
| 504 | timeout_error | the request took too long to answer | A non-streaming turn passed 90 seconds | Retry with stream: true, which has no turn timeout |
Retrying a 429 or 504 is safe: the endpoint holds no state, so nothing was half-written. A 400, 401 or 403 will return the same answer until the cause changes.
Mid-stream
If a stream has already opened, an error arrives as one final data: event whose body is the envelope above, followed by data: [DONE]. The HTTP status of the stream is already 200 by then; read the event.
Catalog and MCP errors
The keyless catalog API has its own shape, {"error": "message"}; see Catalog errors. MCP tool refusals arrive as isError results with a structured code; see Quotas and refusals. Every type and code this endpoint puts in the envelope, and every MCP and tool refusal code, has its own anchor on the Error codes reference. The one exception is the invalid_token above, which is the RFC 6750 bearer error the WWW-Authenticate header carries rather than a Miles refusal code; it is documented here and nowhere else.