---
title: Error Reference
description: 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.
---

import { Callout } from "fumadocs-ui/components/callout";

# Error Reference

## The error envelope

Most `/v1` endpoints return errors in a nested envelope:

```json
{
  "error": {
    "code": "invalid_body",
    "message": "request body did not match the expected schema",
    "details": { "issues": [] }
  },
  "request_id": "req_a1b2c3d4"
}
```

- **`error.code`** is a stable machine-readable string. Safe to branch on in your code.
- **`error.message`** is a human-readable explanation. Surface to users with caution.
- **`error.details`** is optional and per-error. Validation errors put the schema issues here.
- **`request_id`** matches the `X-Request-Id` response 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](/docs/api/wallets).

### 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](https://codespar.dev/dashboard/logs) 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](https://github.com/codespar/codespar/issues) with the `request_id`, timestamp, and expected behavior. See [Debugging](/docs/debugging) for the full bug-report template.

## Next steps

<NextStepsGrid items={[
  { label: "DEBUGGING", title: "Debugging", description: "Logs, tool-call trace, and bug-report template.", href: "/docs/debugging" },
  { label: "REFERENCE", title: "Wallets API", description: "Wallet-specific error codes: ledger conflicts, funding sources, balance invariants.", href: "/docs/api/wallets" },
  { label: "REFERENCE", title: "Sessions API", description: "Session-specific error surfaces.", href: "/docs/api/sessions" },
  { label: "REFERENCE", title: "Triggers API", description: "Webhook delivery errors and DLQ inspection.", href: "/docs/api/triggers" },
  { label: "CONCEPT", title: "Authentication", description: "API key types, scopes, and rotation for 401/403 issues.", href: "/docs/concepts/authentication" },
]} />
