Error Reference
Every error code the CodeSpar API can return, with HTTP status, the response shape, when it fires, and the fix. Aggregated across sessions, projects, connections, triggers, wallets, and auth surfaces.
Error Reference
The error envelope
Most /v1 endpoints return errors in a nested envelope:
{
"error": {
"code": "invalid_body",
"message": "request body did not match the expected schema",
"details": { "issues": [] }
},
"request_id": "req_a1b2c3d4"
}error.codeis a stable machine-readable string. Safe to branch on in your code.error.messageis a human-readable explanation. Surface to users with caution.error.detailsis optional and per-error. Validation errors put the schema issues here.request_idmatches theX-Request-Idresponse header. Include it in support tickets.
The HTTP status is on the response itself, not in the body. Branch on error.code, not on the message text.
Exceptions to the envelope
A few surfaces return a different shape. Detect them by checking whether error is a string or an object:
| Surface | Status | Shape |
|---|---|---|
| Missing, malformed, or revoked API key | 401 | Bare: {"error": "unauthorized"}. No message, no request_id. |
| Key lacks a required scope | 403 | Flat: {"error": "forbidden", "message": "...", "status": 403} |
| Policy denial (including budget rules) | 403 | Flat: {"reason": "budget_exceeded", "ruleType": "...", "ruleId": "..."}, plus approval_id and expires_at when an approval was created |
| Project resolution failure | 500 | Bare: {"error": "project_resolution_failed"} |
| Session quota and rate limits | 403 / 429 | Flat: {"error": "quota_exceeded", ...} or {"error": "rate_limited", ...} with limit fields at the top level |
| Test-mode mock errors | 403 / 422 | Flat: {"code": "mocks_not_permitted", "message": "..."} style, with code at the top level |
| Some legacy routes | 404 | Bare: {"error": "not_found"} |
When the body has no request_id, take it from the X-Request-Id response header.
Error codes
Grouped by area. Each API reference page (/docs/api/*) also lists the errors specific to its surface. Wallet-specific codes (ledger conflicts, funding-source bindings, balance invariants) are also listed on the Wallets API page.
Validation
| Code | Status | When it fires |
|---|---|---|
invalid_body | 400 | The request body did not match the endpoint's schema. details.issues lists the exact field problems. Covers missing fields, wrong types, out-of-range values, and disallowed or reserved project slugs. |
invalid_query | 400 | Query parameters did not match the endpoint's schema. details.issues lists the problems. |
Fix: read details.issues and correct the named fields. The SDK's schemas catch most of these before the request is sent.
Auth and scopes
| Code | Status | When it fires |
|---|---|---|
unauthorized | 401 | No Authorization: Bearer header, the key is malformed, or it was revoked. Bare-string shape (see exceptions above). |
forbidden | 403 | The key is valid but does not have the scope this route requires. The message names the missing scope. Flat shape. |
budget_exceeded | 403 | A policy budget rule denied the call. Appears as reason in the flat policy-denial body, not as error.code. |
project_resolution_failed | 500 | The key authenticated but no default project could be resolved for the account. Bare-string shape. Open a support ticket. |
Fix for 401: verify the key in the dashboard under Settings, API Keys and confirm it is active and sent as Authorization: Bearer csk_....
Fix for 403 forbidden: create a key with the required scope, or widen the existing key's scopes.
Projects
| Code | Status | When it fires |
|---|---|---|
slug_conflict | 400 | Project create or update with a slug another project in the account already uses. Note this is a 400, not a 409. |
cannot_delete_default | 409 | Delete on the default project. Promote another project to default first. |
cannot_delete_last_project | 409 | Delete on the only project in the account. Create another project before deleting this one. |
not_found | 404 | The project id does not exist or belongs to a different account. |
Connections and providers
| Code | Status | When it fires |
|---|---|---|
not_connected | 424 | Connection verification found no active connection for this project and server. Connect the server first, then retry. |
vault_unavailable | 503 | The credential store could not persist or read a secret. Nothing was written; retry with backoff. |
provider_error | 502 | The upstream provider returned an error or an unexpected response. Retriable; retry with backoff. |
Triggers
| Code | Status | When it fires |
|---|---|---|
unknown_server | 400 | Trigger create referenced a server_id that is not in the catalog. |
trigger_not_active | 409 | Test-fire or event delivery on a trigger that is not active. Activate the trigger first. |
invalid_delivery_id | 400 | A delivery id that is not a positive integer was passed to a delivery endpoint. |
Consumer wallet and mandates
| Code | Status | When it fires |
|---|---|---|
mandate_not_found | 404 | The mandate id does not exist or is not visible to this account. |
same_slot_transfer | 422 | Wallet transfer where from_currency and to_currency are the same slot. Nothing to move. |
currency_not_authorized | 422 | Wallet transfer names a currency the wallet has no slot for. Also fires with status 403 on a mandate spend whose payee resolves to a currency the mandate has no slot for. |
unsupported_transfer_route | 422 | No wired route between the two currencies. No FX is ever guessed. |
not_wired | 501 | The transfer route exists in the plan but the execution rail is not wired yet, for example certain cross-currency pairs. |
Test mode
| Code | Status | When it fires |
|---|---|---|
tool_not_mocked | 422 | A session declared mocks but the executed tool has no mock registered. Flat shape with code at the top level. |
mocks_not_permitted | 403 | Mocks declared with a live-environment key. Use a csk_test_ key on a test-environment project. Flat shape. |
Limits
| Code | Status | When it fires |
|---|---|---|
quota_exceeded | 403 | The monthly tool-call allowance for the plan is used up. The flat body includes plan, limit, and used. |
rate_limited | 429 | Per-server rate limit hit on session execution. The response includes a Retry-After header (seconds) and retry_after_ms in the body. |
Fix for 429: respect Retry-After. Exponential backoff with jitter is the canonical pattern.
Debugging
Errors in the standard envelope carry a request_id in the body; every response also carries it in the X-Request-Id header. In the dashboard, search the Logs page for that id to see the full trace: every upstream call, its response body, and timings.
For production support: open an issue at github.com/codespar/codespar with the request_id, timestamp, and expected behavior. See Debugging for the full bug-report template.