Error envelope

Every Cloven error response, on every surface, follows one shape. Branch on code, surface message to humans, log requestId for support.

{
  "error": {
    "code": "pack_access_denied",
    "message": "your key does not have access to pack 'ai'; upgrade to unlock all packs",
    "requestId": "req_01HXY8AB..."
  }
}

The MCP surface wraps the same payload inside the tool error contract:

{
  "isError": true,
  "content": [
    { "type": "text", "text": "pack_access_denied: your key does not have access to pack 'ai'..." }
  ]
}

The SDK throws a typed ClovenApiError carrying code, message, requestId, and status.

Status codes

StatusCodeCauseResolution
400missing_query/v1/search called without qSupply a non-empty q param.
400missing_at/v1/snapshot called without atSupply an ISO8601 at.
400invalid_atat is not a parseable ISO8601Use new Date().toISOString() or equivalent.
400missing_ref/v1/cite called without refSupply integer ref ≥ 1.
400invalid_refref is not a positive integerSupply integer ref ≥ 1.
400invalid_paymentx-payment header malformedRe-encode the proof; confirm base64.
401invalid_tokenBearer/SSE token failed validationRe-issue from /console.
401missing_tokenSSE called without token query paramAdd ?token=cv_….
401key_revokedKey was revoked since last cache refreshIssue a replacement.
402payment_requiredNo auth + no payment proofPay USDC per x402 spec.
402tx_already_settledSame txHash reusedPay a fresh tx for a fresh request.
402tx_too_oldTx confirmed > 10 min agoPay a fresh tx.
402insufficient_paymentTx amount below quoteRe-quote, pay the full amount.
403pack_access_deniedKey tier doesn't include the requested packUpgrade tier or change pack.
404pack_not_foundUnknown pack idCheck cloven://packs or pack catalog.
404snapshot_not_foundNo snapshot at the requested minuteTry a nearby minute; older snapshots require Pro+.
404citation_not_foundref out of range for this packCheck pack.sources.length.
429quota_exhaustedTier quota exceededWait for window roll or upgrade. Retry-After header included.
500internal_errorUnhandled — engineering pagedRetry with backoff; report requestId.
503state_unavailableFirst pulse hasn't landed (cold pack)Retry in 30s.
503brief_unavailablePack hasn't produced first briefRetry in 60s.

Codes are stable

code values are part of the public contract. They will not change without a major version bump. New codes may be added — branch on known codes, default to "log + retry" for unknown ones.

requestId

Every response — success or error — carries X-Request-Id. On errors it's also inlined into the error envelope. Pass it to support and we can pull the full trace (route, pack, source health snapshot, Groq token counts) in one query.

requestId is a ULID — sortable by creation time, safe to log, safe to surface to end users.

Error voice

Cloven error messages are concrete, technical, and never blame the user when the cause is on our side. Read them — they tell you the fix.

  • Good: "your key does not have access to pack 'ai'; upgrade to unlock all packs".
  • Good: "no snapshot found for pack 'crypto' at 2026-05-23T03:04 (snapshots older than 24h require a Pro+ subscription and Postgres lookup)".
  • Bad (we don't do this): "Error occurred. Please try again.".

If you ever see a vague message, file an issue — that's a bug in our error catalog.

Retries

Cloven endpoints are idempotent (the cite endpoint accepts both GET and POST; POST is for symmetry, not state mutation). Safe to retry on 5xx and 429 with exponential backoff. Do not retry on 400/401/403/404 — those errors indicate a request shape problem that retrying won't fix.

x402 retries are special: a 402 means "pay first, then retry". The SDK handles this transparently in wallet mode. If you're rolling your own client, treat 402 as the start of a payment dance, not as a retry condition.

Rate limit detail

The 429 response carries Retry-After: <seconds> indicating when your quota window rolls. The sliding window is per-key. Multiple keys on the same account each have their own window. Plan around the window if you batch — the cleanest pattern is to back off until Retry-After, then resume at half the previous rate.