Errors
Codes are stable and safe to branch on. Messages are written for a human and may be reworded; the code is the contract.
An error is never a substitute for an answer. When a source is
unavailable, an endpoint returns one of these codes. It does not return a
plausible-looking figure, an empty result dressed up as a clean finding, or a
cached value passed off as current.
{
"request_id": "0f1c…",
"service_id": "market-ticker",
"status": "error",
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "The market data source did not respond in time.",
"retryable": true,
"context": { "…": "structured detail, safe to show a user" }
}
} retryable tells you whether the same request could succeed later.
Internals — stack traces, connection strings, provider secrets, file paths — never
appear in an error body.
Your request
Fix the request. No payment was taken, and none was demanded.
| Code | HTTP | Meaning |
|---|---|---|
INVALID_PARAMETER | 400 | A field failed validation. The response names which. |
MISSING_PARAMETER | 400 | A required field was absent. |
INVALID_REQUEST | 400 | The body was not valid JSON, or was not an object. |
REQUEST_TOO_LARGE | 413 | Above this endpoint's published request ceiling. |
UNSUPPORTED_MEDIA_TYPE | 415 | This endpoint expects a multipart upload. |
INVALID_FILE_CONTENT | 422 | The upload's bytes are not what its name claims. |
PAGE_LIMIT_EXCEEDED | 422 | Split the document and retry. |
Payment
Sign a corrected authorisation. Nothing was captured.
| Code | HTTP | Meaning |
|---|---|---|
PAYMENT_REQUIRED | 402 | The challenge. Not a fault — it is the price. |
PAYMENT_INVALID | 400 | The header could not be decoded, or a field is missing. |
PAYMENT_WRONG_AMOUNT | 400 | Does not match the challenge, in either direction. |
PAYMENT_WRONG_RECIPIENT | 400 | Pays somewhere other than the quoted address. |
PAYMENT_WRONG_NETWORK | 400 | Signed for a different chain. |
PAYMENT_WRONG_ASSET | 400 | Signed for a different token contract. |
PAYMENT_EXPIRED | 400 | validBefore had already passed. |
PAYMENT_REPLAY_DETECTED | 409 | That authorisation was already spent. |
PAYMENT_UNSUPPORTED_SCHEME | 400 | The error lists the schemes that would work. |
Upstream and dependencies
Usually worth retrying. These never come back as invented data.
| Code | HTTP | Meaning |
|---|---|---|
UPSTREAM_TEMPORARILY_UNAVAILABLE | 503 | The source did not answer. |
UPSTREAM_TIMEOUT | 504 | It answered too slowly for this endpoint's budget. |
UPSTREAM_RATE_LIMITED | 429 | The source is throttling us. Retry-After is set. |
UPSTREAM_NOT_FOUND | 404 | The source says that resource does not exist. |
RPC_UNAVAILABLE | 503 | The chain node could not be reached. |
INSUFFICIENT_ONCHAIN_DATA | 422 | Not enough on-chain evidence to answer. |
NO_LIQUIDITY_ROUTE | 422 | No pool with enough depth to quote against. |
PROVIDER_NOT_CONFIGURED | 503 | An optional dependency is not installed here. |
AI_PROVIDER_NOT_CONFIGURED | 503 | No model configured. Never invented text. |
AI_OUTPUT_INVALID | 502 | The model could not produce the promised shape. |
Limits and availability
Back off and retry.
| Code | HTTP | Meaning |
|---|---|---|
RATE_LIMITED | 429 | Too many requests. Retry-After is set. |
CONCURRENCY_LIMIT_REACHED | 429 | All slots for this endpoint are busy. |
QUEUE_FULL | 429 | The AI queue is full; the request was not held open. |
SERVICE_IN_MAINTENANCE | 503 | Paused by the operator. |
SERVICE_PAUSED_COST_LIMIT | 503 | Reached its daily upstream cost limit. |
TIMEOUT | 504 | The operation exceeded this endpoint's own limit. |