[ INTEGRATION SURFACE · BETA ] ━━ API, SDKs, and event payloads may change between releases. Read the versioning policy
▸ ROOT / DEVELOPERS/ CONCEPTS/ ERRORS AND RETRIES

Errors and Retries

The error envelope, status codes on the public surface, and which failures to retry.

▸ BETA
▸ APPLIES TO
cheetah service >=0.0.132

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 }
  }
}
  • code is a stable, machine-readable identifier in dotted notation (validation.failed, internal.unknown). Branch on code and the HTTP status, not on message text. Many not-found and request errors currently carry the catch-all unclassified — more specific codes arrive as the API matures, so treat an unrecognized code as you would unclassified.
  • message is human-readable English, for logs and error surfaces.
  • params carries the values interpolated into message.
  • details is 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.

▸ LAST VERIFIED Fri Jun 12 2026 00:00:00 GMT+0000 (Coordinated Universal Time) ▸▸ /content/developers/concepts/errors-and-retries.md
▸ DOCS UNDER CONSTRUCTION LAST UPDATED 2026-07-25 ▸ CHANGELOG