Agent API errors
Every refused request answers with a status code and a JSON body that has an error field, so a script can decide what to do next.
The examples use the ELOWEN_URL and ELOWEN_TOKEN variables set up in Send your first agent API request.
Status codes
| Status | When | Body |
|---|---|---|
400 |
The request body is not valid JSON, a field has the wrong type, or it carries a field the request does not accept. | { "error": "…" } describing the field |
401 |
The token is missing, unknown, deleted or expired, or its value was replaced. | { "error": "unauthorized" } |
402 |
Your account reached its monthly spend limit. A missing model price alone does not cause this refusal. This is the account's limit, not a token limit. | { "error": "spend_limit", "reason": "monthly_limit", "resetsAt": "…" }, where resetsAt is the start of the next UTC month |
403 |
The request needs a signed-in browser session, or your account may not use it. See What a token cannot do. | { "error": "forbidden" } |
404 |
conversationId is not one of your conversations. |
{ "error": "unknown conversation" } |
409 |
The conversation is already running a turn. | { "error": "conversation_busy" } |
409 |
The requested model was refused. | { "error": "…" }, the same message the web app shows |
429 |
A token limit was reached. | { "error": "…", "reason": "…" } and a Retry-After header |
500 |
The turn failed, could not start, or the requested model could not be switched to. With "stream": true, a turn that could not start answers with this status instead of a stream. |
{ "error": "…", "conversationId": "…" } |
503 |
The agent is not available on this server. Also returned when the account's usage could not be recorded, which blocks its paid requests until an administrator reconciles usage and Chetty restarts. | { "error": "brain unavailable" }, or the usage message |
Branch on error, and on reason for a 429, rather than on the message text.
Limit refusals
A 429 always carries Retry-After, the number of seconds to wait, and a reason a script can act on:
error |
reason |
Meaning | Retry-After |
|---|---|---|---|
limit_exhausted |
requests_per_minute |
Too many requests this minute. | Seconds until the minute is over. |
limit_exhausted |
monthly_cost |
This month's cost limit is reached. | Seconds until the next UTC month. |
limit_unverifiable |
monthly_cost_unverifiable |
A turn this month reported no cost, so the cost limit cannot be checked. | Seconds until the next UTC month. |
limit_exhausted |
daily_cost |
Today's cost limit is reached. | Seconds until the next UTC day. |
limit_unverifiable |
daily_cost_unverifiable |
A turn today reported no cost, so the cost limit cannot be checked. | Seconds until the next UTC day. |
limit_exhausted |
concurrent_turns |
Too many runs are still going. | 1 |
When more than one cost limit is reached at once, the answer names the wider window, the month before the day, so Retry-After is a time the run can actually succeed at.
curl -sS -D - "$ELOWEN_URL/api/v1/agent/runs" \
-H "Authorization: Bearer $ELOWEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message":"One more"}'
HTTP/1.1 429 Too Many Requests
Retry-After: 52380
Content-Type: application/json
{"error":"limit_exhausted","reason":"daily_cost"}
What a refused run counts
A run refused by a limit creates nothing: no conversation, no turn, and nothing against the token's turn count.
The same holds for a run refused because the conversation was busy, the conversation or model was unknown, or its turn could not start. A retry after the wait therefore runs as if the refused attempt had never happened.
Related guides
See Cap what an API token can run to set these limits, and Send your first agent API request for a request that succeeds.