Subcore AI Docs
Telemetry read API

Errors

One error envelope, and what each code means.

Every error has the same three fields, plus details on validation failures.

{
  "error": "This API key cannot read telemetry",
  "code": "FORBIDDEN",
  "timestamp": 1788566031707
}
FieldTypeDescription
errorstringA human-readable sentence. Do not match on it; it may be reworded
codestringThe stable machine-readable code. Switch on this
timestampintegerMilliseconds since the Unix epoch, at the moment of the failure

Codes

StatuscodeCauseFix
400VALIDATION_ERRORA query parameter is malformed — a non-integer limit, a from that is not ISO 8601Fix the parameter
400INVALID_CURSORThe cursor is malformed, belongs to a different query, or was editedRestart the listing without a cursor
401AUTHENTICATION_ERRORNo Authorization header, or an invalid or expired keySee authentication
403FORBIDDENThe key lacks permissions.telemetry, or asked for a core outside permissions.coresUse a key with the permission
404NOT_FOUNDNo such session or run in this organization, or none this key may readCheck the id, and the key's core scope
413PAYLOAD_TOO_LARGEAn ingestion body over 10 MB. Reads cannot produce this
429RATE_LIMITEDOver 120 reads per minuteWait Retry-After seconds
500DATABASE_ERRORThe query failed inside SubcoreRetry; if it persists, report it
500INTERNAL_ERRORAn unexpected failureRetry; if it persists, report it

Handling them

Retry 429 and 5xx; do not retry 4xx. A 400, 401, 403 or 404 means the request itself needs to change, and sending it again unchanged will fail identically. On a 429, wait the number of seconds in Retry-After.

Switch on code, not on error. The sentences are written for a human reading a log and are not part of the contract.

INVALID_CURSOR means start over. There is no way to repair a rejected cursor. Drop it and re-page from the beginning, narrowing the time window if you need to avoid re-reading.

if (!res.ok) {
  const { code } = await res.json();
  if (code === "RATE_LIMITED") {
    await sleep(Number(res.headers.get("Retry-After") ?? 1) * 1000);
    return retry();
  }
  if (code === "INVALID_CURSOR") return restartWithoutCursor();
  throw new Error(code);
}

On this page