Cereal docs
HTTP API

Errors

Handle request failures using HTTP status codes and typed error tags.

A failure is always a JSON body with a _tag and the error's own fields, exactly the shape the contract declares.

{
  "_tag": "Forbidden",
  "required": "control",
  "held": ["read", "data"]
}

Branch on the tag. The status is a summary of something you can already read, and it is a pure function of the tag, so the same error means the same status wherever it is raised.

StatusMeaningExamples
400The request is not acceptable input. A body that does not decode lands here as BadRequest.MetadataFilterInvalid, MetadataTooLarge, BlobTooLarge, TtlTooLong, RetentionInvalid
401No usable credential.Unauthorized, carrying a reason: unknown, revoked, expired
402The spend cap.SpendLimitExceeded
403A credential that is fine, refused for what it asked.Forbidden, carrying required and held for a scope, or a reason of not_a_member, environment_mismatch (an environment header conflicts with the API key)
404It is not here.every *NotFound
409It is already there, or it moved.ProviderSlugTaken, ConnectionSlugTaken, EnvironmentSlugTaken, VersionConflict
422Understood, and refused on its merits.OverrideNotAllowed, ProviderInUse, SecretInUse, AgentNotReady, AgentCopyUnresolved, DecisionExpired, ConnectionError, ProviderError

Decide whether to retry

For SpendLimitExceeded (402), raise the cap or wait until resetsAt. For VersionConflict (409), read the current version before submitting another update. For OverrideNotAllowed (422), change the requested override or the agent's policy. A not-found response can mean the resource does not exist in the selected environment.

Use a stable idempotency key when retrying a session creation or message send after a transport failure. See delivery modes.

In the SDK

Typed failures arrive as CerealError subclasses, each carrying the wire tag and the server's fields under data.

import { SpendLimitExceededError, DecisionExpiredError } from "@trycereal/sdk"

try {
  await client.sessions.send({ id, message })
} catch (error) {
  if (error instanceof SpendLimitExceededError) {
    console.warn(`${error.scope} out of ${error.metric} until ${error.resetsAt}`)
    return
  }
  throw error
}

A tag this version of the SDK does not know still arrives as a CerealError with that tag, so a contract addition never breaks an older client. Transport and validation problems are CerealTransportError and CerealValidationError.

On this page