Skip to main content

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.

3 min read
View MarkdownEdit on GitHub

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.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:

SurfaceStatusShape
Missing, malformed, or revoked API key401Bare: {"error": "unauthorized"}. No message, no request_id.
Key lacks a required scope403Flat: {"error": "forbidden", "message": "...", "status": 403}
Caller's account role is too low403Flat: {"error": "insufficient_role", "required": "admin"}
Policy denial (including budget rules)403Flat: {"reason": "budget_exceeded", "ruleType": "...", "ruleId": "..."}, plus approval_id and expires_at when an approval was created
Project resolution failure500Bare: {"error": "project_resolution_failed"}
Session quota and rate limits403 / 429Flat: {"error": "quota_exceeded", ...} or {"error": "rate_limited", ...} with limit fields at the top level
Test-mode mock errors403 / 422Flat: {"code": "mocks_not_permitted", "message": "..."} style, with code at the top level
Some legacy routes404Bare: {"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.

The tables below are extracted from the backend's two error-emitting shapes — the apiError() helper (the standard envelope) and the routes that answer with reply.code(4xx) and a flat body — and cover the routes an API key or a public gateway can reach: 174 codes, which is every row below. What is deliberately not listed: operator-only subtrees (admin provisioning, the engine console, service-auth surfaces like billing and api-keys) and provider webhook receivers, whose codes no caller can trigger; and any error a provider returns, which reaches you wrapped as provider_error. Codes are grouped by the surface that emits them, so the same code can appear once with the status its call site actually sends.

Validation

CodeStatusWhen it fires
invalid_body400The 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_query400Query 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

CodeStatusWhen it fires
unauthorized401No Authorization: Bearer header, the key is malformed, or it was revoked. Bare-string shape (see exceptions above).
forbidden403The key is valid but does not have the scope this route requires. The message names the missing scope. Flat shape.
budget_exceeded403A policy budget rule denied the call. Appears as reason in the flat policy-denial body, not as error.code.
insufficient_role403The caller's account role is below what the route requires (admin on most administrative writes). The most common 403 in the product. Two shapes: the requireRole guard answers flat — {"error": "insufficient_role", "required": "admin"} — while a handful of route handlers answer it in the standard envelope. It also fires when the acting user is not forwarded at all on a service-auth call (x-codespar-user header required).
project_resolution_failed500The 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_....

401 on api-keys, usage, billing, team and project members

Those five surfaces are registered in the API's service-auth subtree. A csk_ Bearer key is not read there at all, so any Bearer call to them answers 401 unauthorized — not 403, not 404. No key we can issue changes that: the credential for that subtree is CodeSpar's own platform secret and never leaves our infrastructure. Reach those surfaces through the dashboard. See the Billing page.

Fix for 403 forbidden: create a key with the required scope, or widen the existing key's scopes.

Projects

CodeStatusWhen it fires
slug_conflict400Project create or update with a slug another project in the account already uses. Note this is a 400, not a 409.
cannot_delete_default409Delete on the default project. Promote another project to default first.
cannot_delete_last_project409Delete on the only project in the account. Create another project before deleting this one.
cannot_delete_with_consumer_records409Delete on a project that still owns consumer records. Move or close them first.
not_found404The project id does not exist or belongs to a different account. Also returned by project-settings and by the member endpoints when there is no override row for the named user.
user_not_in_org404A project-member write named a user_id that is not a member of this account.
cannot_override_owner409A project-member write targeted the account owner. An owner's role is never narrowed per project.

Connections and providers

CodeStatusWhen it fires
not_connected424Connection verification found no active connection for this project and server. Connect the server first, then retry.
server_unknown404The server_id is not in the catalog.
not_api_key_server400The server authenticates with OAuth; credentials cannot be posted to the API-key endpoint. Use POST /v1/connect/start.
credential_invalid400The supplied secret could not produce an HMAC — the credential is malformed for this server's signing scheme.
invalid_secret_shape400The secret payload does not match the shape the server's auth scheme declares.
path_secret_keys_mismatch400The secret object's keys do not match the server's declared path-secret refs.
no_user_fields400The connection declares no user-editable fields; re-connect through the modal to change credentials.
fields_not_user_editable400A PATCH named keys outside the server's requires_user_fields. The message lists the rejected keys.
provider_has_no_inbound_webhooks400Webhook-secret rotation on a server that does not support inbound webhooks in this API.
user_id_required400The connection owner could not be determined. Pass user_id, or forward x-codespar-user.
metadata_update_failed409The connection row disappeared between the read and the write. Re-read and retry.
vault_unavailable503The credential store could not persist or read a secret. Nothing was written; retry with backoff.
provider_error502The upstream provider returned an error or an unexpected response. Retriable; retry with backoff.

Sandbox subaccount provisioning

CodeStatusWhen it fires
not_test_environment422The provisioning lane is sandbox-only. A live-environment project cannot be engine-provisioned.
not_awaiting_verification409A verification code was submitted for a run that is not waiting on one.
run_stale410The paused provisioning run expired. Start a new one.
insufficient_role403The operator-internal status/revoke steps require service auth, not a Bearer key.

Triggers

CodeStatusWhen it fires
unknown_server400Trigger create referenced a server_id that is not in the catalog.
trigger_not_active409Test-fire or event delivery on a trigger that is not active. Activate the trigger first.
trigger_not_found404An event replay named a trigger that does not exist in this account.
trigger_event_mismatch400The replay target subscribes to a different event type than the event being replayed.
invalid_delivery_id400A delivery id that is not a positive integer was passed to a delivery endpoint.

Consumer wallet and mandates

CodeStatusWhen it fires
mandate_not_found403 / 404The mandate id does not exist or is not visible to this account.
mandate_not_active409The mandate's status forbids the operation (for example binding a card to a revoked mandate).
mandate_already_revoked409Revoke on a mandate that is already revoked.
mandate_already_expired410The mandate's expires_at has passed. Mint a new one.
mandate_agent_key_invalid403The agent key that signed the mandate is revoked, or was not valid when the mandate was issued.
mandate_purpose_required400The mandate carries several purposes; name which one this spend is charged against.
invalid_purpose_encoding400A purpose string contains non-printable or non-ASCII characters.
expires_at_in_past400expires_at must be a future UNIX timestamp.
missing_required_field400A required field is absent from the mandate or facilitator request body.
invalid_transition409The requested action is not legal from the mandate's current status.
transition_conflict409The mandate's status changed concurrently. Re-read and retry.
same_slot_transfer422Wallet transfer where from_currency and to_currency are the same slot. Nothing to move.
currency_not_authorized422Wallet 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_route422No wired route between the two currencies. No FX is ever guessed.
not_wired501The transfer route exists in the plan but the execution rail is not wired yet, for example certain cross-currency pairs.

Wallet ledger and funding sources

CodeStatusWhen it fires
wallet_not_active409The wallet's status is not active; only active wallets accept ledger entries.
ledger_conflict409The entry violated a unique constraint other than the idempotency one — a replay of the same idempotency key is handled and returns the existing row with 200, so this signals a genuine conflict.
balance_constraint_violation409The entry would violate a wallet balance invariant — a debit past the available balance, for example. Nothing is written.
connection_not_found404The connection named as a funding source is not in this account.
connection_not_active409The connection exists but its status is not connected.
funding_rail_mismatch409The provider does not settle in the slot's currency. Bind a provider whose rail matches.
funding_source_conflict409That connection is already bound to a wallet for this currency.
funding_source_not_found404The funding-source binding does not exist.
no_onchain_wallet409On-chain withdrawal is only available for consumer-scoped wallets.
no_onchain_address409On-chain receive is only available for consumer-scoped USDC wallets.
no_custody_view409The custody comparison is only available for on-chain USDC wallets.
anomaly_not_found404The recon anomaly id does not exist, or is already resolved.

Consumer funding and receipts

CodeStatusWhen it fires
no_celcoin_account422The consumer has no active BaaS funding source and no account was supplied. Run KYC onboarding first.
sandbox_funding_not_permitted403Sandbox funding was requested with a live-environment key. Use a csk_test_ key on a test-environment project.
transaction_not_found404The onramp transaction does not exist, or the onramp provider is not connected.
receipt_not_found404No agentic receipt exists for that id.

Card issuing

CodeStatusWhen it fires
issuer_corridor_unsupported400No enabled issuer serves the (country, currency) corridor. Issuers are enabled per deployment by an infrastructure flag; see codespar_issue.
issuer_controls_unsupported400The mandate's currency cannot govern a card in the requested currency.
issuer_card_unknown404The mint flow or card id is unknown to this account.
invalid_holder400The cardholder identity payload is incomplete or malformed.
holder_already_registered409That holder identity is already registered to another tenant at the issuer.
mandate_already_bound409The mandate already backs an active card or a live mint flow — one card per mandate.
mandate_already_has_card409The mandate already has an active card binding; revoke it before binding another.
no_active_card404The mandate has no active card binding to revoke.
cross_tenant_card409The card belongs to another tenant.
idempotency_key_conflict409An Idempotency-Key was reused with a different request body. A changed body is a new request: use a new key.
live_issuer_test_key403This deployment issues real cards; a test-mode key cannot mint.
stage_issuer_live_key403This deployment issues stage cards; a live-mode key cannot mint.
simulate_not_allowed403The card-authorization read-back only runs against a non-production issuer environment.
CodeStatusWhen it fires
consent_expired410The consent token in the URL has expired. Issue a new one.
consent_already_resolved409The consent was already approved or denied.
consent_active_for_consumer409The project already holds an open consent for this consumer at this bank. Revoke it before issuing another.
consent_not_authorised409The operation needs a consent in the authorised state.
illegal_transition409The requested consent status change is not legal from the current state.
db_error409The consent could not be persisted. Retry.

Hosted MCP servers

CodeStatusWhen it fires
mcp_server_not_found404No active MCP server for that slug.
mcp_tool_not_found404The named tool does not exist on that server.
invalid_upstream_url400upstream_url must be a public http(s) URL.
slug_conflict409An MCP server with that slug already exists. Slugs are global.
sweep_in_progress409A tool sweep for this account is already running. Try again shortly.
CodeStatusWhen it fires
paywall_not_found404No active paywall for that slug.
payment_link_not_found404No active payment link for that slug.
pricing_model_unsupported400Only flat, tiered, dynamic and metered paywall pricing are live.
invalid_tiers400Tiered pricing needs at least one tier.
invalid_dynamic_price_url400Dynamic pricing needs a public http(s) price-hook URL.
invalid_metered_config400Metered pricing needs a metered_config block.
metered_not_enabled400Metered pricing is not enabled on this deployment.
metered_requires_provisioned400Metered pricing needs a provisioned payTo — refunds settle from a wallet we control.
invalid_payto400A bring-your-own x402 payTo must be a 0x EVM address.
invalid_rail400The payment link declares the same rail twice.
malformed_authorization400The Authorization payload on a gateway call is not the expected shape.
invalid_mandate400The mandate presented at the gateway is missing agent_id or purpose.
payment_link_env_mismatch409The mandate's environment does not match the link's environment.
no_pix_method422The payment link has no Pix settlement method.
idempotency_in_progress409A request with this Idempotency-Key is still processing. Retry shortly.
method_not_allowed405The paywall does not front that HTTP method.

Agent identity, audit and memory

CodeStatusWhen it fires
agent_not_found404The agent id or did:web document does not resolve.
org_id_not_did_safe400The account id contains characters a did:web path segment cannot carry.
agent_id_not_did_safe400The agent id contains characters a did:web path segment cannot carry.
agent_already_registered409An agent is already registered under that handle in this account. Rotate its key instead of re-registering.
agent_did_owned_elsewhere409The derived did:web is registered to a different tenant. Register under a different handle.
no_active_key409Rotate was called on an agent that has no active key to rotate.
agent_key_not_found404The key id does not exist for this agent.
key_already_revoked409Revoke on a key that is already revoked.
issuer_not_provisioned404The platform issuer has no did:web document yet.
cross_org_verify_denied403The anchor's account does not match the caller's.
counterparty_not_found404The counterparty does not belong to this account and project.
foreign_authorization_not_found404The facilitator has no record of that foreign authorization.

Sessions and tool execution

CodeStatusWhen it fires
unknown_servers400Session create named one or more servers that are not in the catalog.
server_not_connected400Execution named a server this project has no active connection for.
session_not_active409The session was closed or expired; open a new one.
credentials_unavailable424The credential for the resolved provider could not be read at dispatch. Nothing was sent upstream.
invalid_tool_call_id400The tool_call_id in a status or verification-status path is not a well-formed id.
tool_call_not_found404No tool call with that id in this project.
chaos_invalid400A chaos block that does not match { fail_provider, meta_tool?, remaining: 1-3, reason }.
chaos_not_permitted400Chaos rules were declared with a live-environment key. Use a csk_test_ key.
payload_too_large413The request body exceeded the guardrail middleware's ceiling.

Scope enforcement

These come from the scope guard rather than a route handler, and all three carry the flat forbidden-style shape.

CodeStatusWhen it fires
route_scope_unmapped403The route carries no scope mapping and the deployment refuses unmapped routes (ROUTE_SCOPE_DENY_UNMAPPED). Off by default — see Authentication.
route_scope_unresolved403Scope enforcement could not resolve the matched route template. Alarm-grade; report it.
scopes_unresolved403Scope enforcement could not resolve the caller's scopes. Alarm-grade; report it.

Approvals

CodeStatusWhen it fires
approval_not_found404No approval with that id is visible to this account.
already_decided409The approval was already approved or rejected. Its decision is final.
expired410The hold expired before anyone decided. The call never ran.
bearer_token_cannot_decide403A project API key tried to decide. Deciding is service-auth only, so a leaked csk_ key cannot release a held payment.
user_token_required403The decide call carried no user token and the deployment enforces one (APPROVAL_DECIDE_ENFORCE_USER_TOKEN).
user_token_invalid403The user token failed verification.
user_token_identity_mismatch403The x-codespar-user header disagrees with the verified token's sub.
rate_limit_exceeded429Decide throttle hit. The body carries retry_after_seconds and the response a Retry-After header.
bearer_token_cannot_manage_policies403Same posture on policy writes: a project API key cannot edit the rules that gate its own spend.

Audit chain and incidents

CodeStatusWhen it fires
invalid_iso_8601400A from / to value is not an ISO-8601 timestamp.
from_after_to400The window's start is after its end.
invalid_before_sequence400The pagination cursor is not a valid sequence number.
invalid_user_id400The user_id filter is malformed.
export_too_large413The requested export exceeds the size ceiling. Narrow the window.
unauthenticated401The incident surface requires an authenticated principal.
human_session_required403Acknowledging an incident requires a signed-in human, not a key.
incident_not_found404No incident with that id in this account.
already_acknowledged409The incident was already acknowledged.
invalid_status400The target status is not one this incident can take.
field_invalid400A named field failed validation; the body says which.
window_ordering_invalid400The assessment window's bounds are out of order.
pending_assessment_not_terminal400The assessment is still open; it cannot be closed from this state.
regulatory_minimum_violation400The submitted values fall below a retention or disclosure minimum the surface enforces.
CodeStatusWhen it fires
server_oauth_not_configured404POST /v1/connect/start named a server with no OAuth configuration.
invalid_state400The callback's state is unknown, expired, or already consumed. Links live 10 minutes and are single-use.
missing_code_or_state400The provider redirected back without the parameters the exchange needs.
provider_error_without_state400The provider reported an error and sent no state, so there is nowhere to redirect the user.
server_mismatch400The callback's server does not match the one the state row was minted for.
invalid_or_expired_state400Same failure on the storefront connect flow. Restart it.
auth_required401The storefront connect flow was reached without a session.
cannot_delete_active409Delete on a connection that is still active. Revoke it first.

Cart, sellers and KYC onboarding

CodeStatusWhen it fires
cart_search_failed422The store search leg failed upstream. Retriable.
cart_session_failed422The store checkout session could not be opened. Retriable — see codespar_shop's retriable reason codes.
seller_not_found404No seller with that id in this account.
document_number_required400The onboarding call needs the subject's document number.

MCP Generator and hosted MCP

CodeStatusWhen it fires
project_required400The generate call did not resolve a project.
invalid_spec400The supplied OpenAPI document could not be parsed.
github_fetch_failed422The GitHub source could not be fetched.
no_endpoints422The scan found no endpoints to expose.
generated_server_unknown404No generated server with that id in this project.
invalid_or_missing_mcp_session_id400The remote-MCP transport was called without a valid Mcp-Session-Id.

Test mode

CodeStatusWhen it fires
tool_not_mocked422A session declared mocks but the executed tool has no mock registered. Flat shape with code at the top level.
mocks_not_permitted403Mocks declared with a live-environment key. Use a csk_test_ key on a test-environment project. Flat shape.

Limits

CodeStatusWhen it fires
quota_exceeded403The monthly tool-call allowance for the plan is used up. The flat body includes plan, limit, and used.
rate_limited429Per-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.

Next steps

Error Reference | CodeSpar