camelAI Documentation

API Reference

camelRun errors: HTTP codes, failed runs and tools

camelRun's HTTP errors, failed runs, and tool calls that didn't complete: what each means and what to do about it.

View as Markdown · Docs index for coding agents

There are three kinds of failure:

  1. The API refused a request. An HTTP status and a JSON body. The SDKs throw AgentError with status and code.
  2. A run failed. The request was accepted, and the run ended badly. The SDKs' run() throws RunError with the run, unless throwOnError: false (Python throw_on_error=False).
  3. A tool call didn't complete within a run that otherwise went on. The model was told, and the run lists it in toolErrors. Nothing throws.

HTTP errors

Error bodies are {"error": "<message for people>", "code": "<CODE>"}. The message may change and the code won't, so switch on code. New codes may be added; treat an unknown one by its status. A conflict about an input also carries the input as it now is (input), and a rate limit's 429 the limit it hit (limit). Every 429 and 503 has Retry-After (and a per-account rate limit's 429 its X-RateLimit-* headers; see Limits), and the SDKs honor it and retry.

StatuscodeMeaningWhat to do
400INVALID_REQUESTMalformed or invalid; the message says howFix the request
400INVALID_HISTORYAn imported initialMessages has a message it can't takeFix the named message
400FORK_POINT_INVALIDA fork's atMessage is no index in the history, nor a request id in itCheck the index or id
400TRANSCRIPTION_UNAVAILABLE, REALTIME_UNAVAILABLE, IMAGE_UNAVAILABLEAudio was to be transcribed, a voice session needs a realtime provider, or an image was to be made, and the account has no key for it (nor the platform's)Add the key the message names
400IMAGE_REFUSEDOpenAI's safety system refused the request (stage: "input") or the image (stage: "output"); categories says why. Nothing was chargedChange the prompt
401UNAUTHORIZEDNo valid token, or an expired browser tokenSend a valid key; mint a new browser token
402SPEND_LIMITThe agent's spend limit, or the account's monthly cap; or a message's audio, or an image, would cost more than the limit has leftRaise the limit
402INSUFFICIENT_CREDITThe account's prepaid credit is spent (or a payment for it is disputed): no runs start and no files are storedAdd credit in the console
402END_USER_CREDITWith end-user credits on, the call's end user may not spend more in its bucket. The body has endUser, bucket and reason (below)Grant them credit, raise the limit, or wait for tomorrow's allowance. See When a person runs out
403FORBIDDENThe token may not do this, such as a browser token outside its agentUse your API key, server-side
404NOT_FOUNDNo such agent, request, input or other resource in your accountCheck the id
409IDEMPOTENCY_CONFLICTThe Idempotency-Key or request id was used for another requestUse a new key for a new request
409IDEMPOTENCY_IN_PROGRESSThe first request with this key is still runningRetry shortly
409INSUFFICIENT_BALANCEAn end user's refund would return more than their balance not held by calls in flight; refundable is the most it may return nowRefund less, or post an adjustment. See End-user credits
409CARD_CREDIT_UNAVAILABLECard-verification starting credit isn't offeredBuy credit instead
409VOICE_SESSION_EXISTS, VOICE_SESSION_ENDED, VOICE_SPEAK_DISABLEDThe bot already has a voice session in this server (session), the session ended, or it only listensUpdate or end it; start a new one; don't ask a listening session to speak
409APPLICATION_CONNECTEDAnother process serves this agent's toolsClose it, pass takeover: true, or connect with attach: false
409APPLICATION_NOT_CONNECTEDThe agent's tools need their process and none is connectedStart it, serve tools over HTTP, or pass allowDisconnected: true
409FORK_POINT_RUNNINGA fork's atMessage is in a turn that hasn't endedFork at an earlier message, or once it ends
409REPLAY_GAPThe Last-Event-ID is behind the replay bufferReconnect with ?snapshot=1 and read /state
409CONFLICTAnother conflict, named in the messageSee below
410GONEThe agent was deleted or expiredUpsert the key again for a fresh agent
413TOO_LARGEThe request body is too largeUpload large files first and attach them by path
413HISTORY_TOO_LARGEAn imported history is over 16 MBSend recent messages after a compactionSummary
413AUDIO_TOO_LARGE, AUDIO_TOO_LONGAudio to transcribe is over 25 MB or 30 minutes (a message's: 5 files or 30 minutes in all)Split it
413IMAGE_TOO_LARGEAn image to edit is over 25 MB or 8,000 pixels a side, or a request's images are over 50 MB in allSend smaller images
415UNSUPPORTED_AUDIO, UNSUPPORTED_IMAGEAudio in a format transcription doesn't take, or an image to edit that isn't PNG, JPEG or WebPConvert it
429BUSY_AGENT_LIMITAs many agents are busy as your usage tier allows; busyAgents has the limit and the next tierRetry after Retry-After, or when one of its runs ends
429VOICE_SESSION_LIMITAs many live voice sessions as the account may have (limit)End one first
429RATE_LIMITEDA rate limit (limit names it: {name, scope, max, windowSeconds}), or too many agents, requests or subscribers at onceRetry after Retry-After
502TRANSCRIPTION_FAILED, IMAGE_FAILEDThe provider failed or refused the key; nothing was chargedRetry, or check the key
503UNAVAILABLEcamelRun is restarting or deploying, or an agent is movingRetry after Retry-After; nothing happened
503DATABASE_RETRYThe database refused the request for nowRetry after Retry-After
507STORAGE_LIMITThe account's storage limit would be passed; the body has limit and used, in bytesDelete files or volumes, or buy credit (free credit stores 1 GB)
500INTERNALA bugRetry, and report it with the request id

Common CONFLICT cases:

  • An existing agent's subject, context, definition or mounts can't change. An upsert of an existing key changed a field that's set only at creation. Delete the agent or use another key. For mounts, send remount: true with the upsert instead (see Volumes).
  • This input is already answered. Someone answered first. The body's input says how it settled. Answering again the same way is a 200.
  • The definition is at revision N, not M. A definition update with a stale revision. Read it again and retry.

Run failures

RunError.codeMeaning
model_key_missingNo key is set for the agent's model. The error names the model and the remedy: set a key with PUT /v1/providers/{provider}/key (or the key scope's entry), or move the agent to a model you can use (GET /v1/models?available=true)
model_key_invalidThe provider refused the key (HTTP 401). The error says the same remedy, then the provider's own words
model_errorThe model provider refused or failed after 3 retries for transient failures: a bad request, refused content, or a context overflow compaction couldn't fix
output_missingA run sent with output ended without the model calling final_output: it answered in prose twice, the second time after a reminder. text has what it said. Send the prompt again, make the instructions say what the answer is for, or use a stronger model
output_invalid(SDKs only) The output fit the JSON Schema camelRun checked, but not the zod or pydantic schema the SDK parsed it with
model_stream_stalledThe model stopped answering mid-request, past every retry
spend_limitA spend limit stopped the turn after the response that crossed it, or refused the run as it left the queue. result.limit says which: run, agent, tenant (the monthly cap) or credit (prepaid credit spent). Raise that limit and send the next message
turn_limitThe run made as many model responses (1,000 by default) or ran as long (2 hours) as its run limits allow. Send another message to continue, or raise the agent's runLimits
end_user_creditThe run's end user may not spend more (limit: "end_user", with reason, bucket and endUser). Not retried. Grant them credit and send the next message. See When a person runs out
aborted, cancelledThe agent was stopped while the run went, or a stop cancelled the run before it began
resume_limitThe run was interrupted again after two resumes. The agent takes new messages
runtime_errorcamelRun couldn't carry out the run: for example, the agent was deleted

Over REST, an ended request record (GET /v1/agents/{id}/requests/{requestId}) has status on top: completed, input_required or failed, as the SDKs' runs say it. Its state says only whether it ended (running, completed), so a failed run is state: "completed", status: "failed", with error saying why.

A run with uncertain: true was cut short by a restart where it couldn't resume. Its tool calls may or may not have taken effect, so check before retrying.

A run interrupted mid-turn (camelRun restarted under it) resumes (turn_resumed), with any tool call whose answer was lost marked "outcome unknown" for the model. Tool calls are never sent twice. After two such resumes, another interruption fails the run with resume_limit. A deploy loses nothing: the turn moves at a step boundary.

End-user credit reasons

A 402 END_USER_CREDIT, a run's end_user_credit, the run.failed webhook and voice.session.ended's endUserReason all carry reason, bucket and endUser. reason is one of:

reasonMeaningWhat the end user can do
balanceToday's free allowance in the bucket is used up, and their paid balance has nothing leftAdd credit (a grant), or wait for tomorrow's allowance
daily_limitTheir own daily limit on paid spend is reachedWait for tomorrow, or have the limit raised
bucket_limitThe bucket's daily limit on paid spend is reached. A bucket limited to 0 spends only its free allowanceWait for tomorrow, or have the bucket's limit raised

More reasons may be added: treat one you don't know as a credit refusal of no particular kind.

Model failures

When a model call failed the run (model_error, model_stream_stalled, model_key_invalid and the like), its error says how, so you needn't parse message:

json
{ "code": "model_error", "message": "402 This request requires more credits…",
  "errorClass": "billing", "providerStatus": 402, "retryable": false, "model": "openrouter/anthropic/claude-sonnet-5" }
FieldMeaning
errorClassbilling (the provider's 402, or a quota used up), rate_limit, server (5xx, overloaded, unreachable), refusal (the model declined, or a safety filter stopped it), auth (401, 403, no key), timeout, other. Treat an unknown class as other
providerStatusThe provider's HTTP status, when its error gives one
retryableWhether camelRun retries this kind of failure itself (3 times, with backoff). On a failed run, true means it was transient and the retries ran out, so trying later or with another model may work. A model on your own endpoint isn't retried, except for a stalled stream, so its failures are false
modelThe model that failed, as provider/model-id

The same fields are on the run.failed webhook. A run's servedModel is the model that made its last response.

Tool errors

A run lists each tool call that didn't complete as toolErrors: [{tool, toolCallId?, code, outcomeUnknown?, message}]. The model got the same message and carried on.

codeMeaningOutcome unknown
timeoutNo answer or progress within the tool's deadlineYes
connection_lostThe connection closed before the answer arrivedYes
not_connectedNo process served the agent's attached tools, so the call didn't run. Typical for REST, schedules and channels driving an agent whose tools live in a process that isn't running: serve them over HTTP insteadNo
source_unavailableIts MCP server couldn't be reached, listed or authenticated with, or its credential exchange gave no credential the server takesNo
failedAnything else that kept it from runningNo

A tool that ran and reported its own failure (threw, or answered isError) is not a tool error: that's the tool's answer, which the model reads.

SDK errors

TypeScriptPython
Any failureAgentError: message, status, code, requestId, uncertain, retryAfterMsAgentError: status, code, request_id, uncertain, retry_after
A failed runRunError extends AgentError, with runRunError, with run
An end user's credit refusedreason, bucket, endUser; endUserCredit(errorOrRun)reason, bucket, end_user; end_user_credit(...)
Another process took the agent's toolscode: "APPLICATION_REPLACED", through onErrorThe same, through on_error
A served tool's token check failedRuntimeTokenErrorRuntimeTokenError

A run's failure is not an HTTP response, so RunError.status is always 0, in both SDKs: it does not mean the network failed. Branch on code (model_key_missing, spend_limit, …). An AgentError with status 0 and no code is the connection's failure.

Stopping a wait (signal, or Python timeout) doesn't stop the run. Wait for it again with the same idempotencyKey.