Errors and Retries
The error envelope, status codes on the public surface, and which failures to retry.
The error envelope#
Every error response, regardless of status code, carries one shape:
{
"error": {
"code": "unclassified",
"message": "Run 0196a3f2-7c1e-7d2a-b3a4-9e8d1c2b3a4f not found",
"params": {},
"details": { "status_code": 404 }
}
}
codeis a stable, machine-readable identifier in dotted notation (validation.failed,internal.unknown). Branch oncodeand the HTTP status, not onmessagetext. Many not-found and request errors currently carry the catch-allunclassified— more specific codes arrive as the API matures, so treat an unrecognized code as you wouldunclassified.messageis human-readable English, for logs and error surfaces.paramscarries the values interpolated intomessage.detailsis free-form diagnostics. Don't pin on its keys — it's not a stable surface.
Validation failures (422) enumerate the offending fields under details.fields:
{
"error": {
"code": "validation.failed",
"message": "Request validation failed",
"params": {},
"details": {
"fields": [
{
"field": "query.limit",
"type": "less_than_equal",
"message": "Input should be less than or equal to 1000",
"ctx": { "le": 1000 }
}
]
}
}
}
Status codes on the public surface#
| Status | When | Retry? |
|---|---|---|
400 |
The request can't be satisfied as posed — e.g. requesting cl_sweep.csv for a step that isn't a CL sweep |
No — fix the request |
404 |
Unknown id, or a file format that doesn't exist for that frame | No — but see below |
422 |
A parameter failed validation (limit out of range, malformed timestamp) | No — fix the request |
500 |
Unhandled error in the service | Yes, with backoff |
503 |
A component the request needs is down | Yes, with backoff |
One nuance on 404: a run_id you just received from an event will exist. But raw-data files are written as a program run executes — a frame file requested mid-run can be a 404 that becomes a 200 once the program run completes. Treat a 404 for very recent data as "not yet" and check again after the program run is terminal; treat any other 404 as wrong id.
What to retry#
Retry connection errors, timeouts, 500, and 503 — the surface is read-dominant, so retrying is always safe. Use exponential backoff with jitter and a cap, on the order of: 1 s, 2 s, 4 s … capped at a minute. A cell that's offline stays offline for a while — after a few attempts, switch from retrying to alerting, and let your sync loop catch up when the cell returns.
Never blind-retry a 4xx — the request itself is wrong, and it will be wrong again.
Poll like a good citizen — the loop patterns on the Open REST API page need seconds-scale intervals, not tight loops.
When you report a problem#
Every response — success or error — carries an X-Trace-ID header that identifies the request in the cell's logs. Log it alongside your own request records, and include it when you contact support.