ErrorsReference
When a call fails, the response tells you why. To handle an error:
- Read
error.codein the body. It is the precise reason. - Find the code in the tables below, grouped by cause.
- Apply the fix in the What to do column.
Errors are OpenAI-shaped, so any OpenAI client shows them sensibly:
{
"error": {
"message": "The model 'gpt-9' does not exist on api.kaer.ai.",
"type": "invalid_request_error",
"param": null,
"code": "model_not_found"
}
}type is the OpenAI class; code is the precise reason, so branch on code. A call that fails with an error status is not charged; a stream that breaks after it started is charged for what it sent. The maps service's own errors keep their shape, see Maps.
Keys and access
| Code | Status | Meaning | What to do |
|---|---|---|---|
missing_api_key | 401 | No key in Authorization: Bearer or x-api-key. | Send your key. |
invalid_api_key | 401 | The key is malformed, unknown, revoked or expired. | Check the key, or create a new one. |
account_inactive | 403 | The account is suspended or closed, or owes a reversed payment. | If the message mentions a balance owed, add credit. Otherwise write to [email protected]. |
ip_not_allowed | 403 | The caller's IP is not on the key's allow-list. | Add the address or range to the key, or call from an allowed host. |
insufficient_scope | 403 | The key does not have the endpoint's scope. | Add the scope to the key in the dashboard. |
tier_required | 403 | Your tier does not include this service yet. | Search, images and maps open at Starter ($5 paid). Mail opens at Build. |
unknown_endpoint | 404 | No such endpoint under /v1. | Check the path against this page. |
not_found | 404 | The path is not part of the API. | Call https://api.kaer.ai/v1/.... |
Balance and spend
| Code | Status | Meaning | What to do |
|---|---|---|---|
insufficient_credits | 402 | Your balance cannot cover the call's hold. Free credit never pays for mail. | Top up, turn on automatic top-up, or lower max_tokens to shrink the hold. |
monthly_limit_reached | 402 | This month's spend plus open holds would pass your monthly cap (your budget or your tier's). | Raise your budget in Settings, move up a tier, or wait for the new month (UTC). |
key_budget_exceeded | 402 | The key's monthly budget is used up. Open holds count. | Raise or clear the key's budget. |
payment_required | 402 | A refunded or disputed payment left a balance owed. | Add credit to clear it. |
Rate limits
| Code | Status | Meaning | What to do |
|---|---|---|---|
rate_limit_exceeded | 429 | Too many requests this minute for the key or the account, or too many invalid keys from your address. | Wait for Retry-After, then back off. See Rate limits and tiers. |
too_many_streams | 429 | Your account already has its tier's maximum of open streams. | Wait for a stream to finish. |
key_shared | 429 | A Free tier key was used from too many networks within an hour. | Keep keys on your server. A top-up moves you off the Free tier. |
mail_rate_limit | 429 | Messages in the last minute reached your tier's cap. | Wait 60 seconds (Retry-After). |
mail_daily_limit | 429 | Recipients today (UTC) would pass your tier's cap. | Wait until 00:00 UTC (Retry-After) or move up a tier. |
Request
| Code | Status | Meaning | What to do |
|---|---|---|---|
invalid_json | 400 | The body is not valid JSON. Images also needs a JSON object. | Send a JSON object with Content-Type: application/json. |
body_too_large | 413 | The body is over the endpoint's limit: chat 1 MB, search 16 KB, batch 64 KB, images 8 KB, mail 512 KB. | Send less. |
model_required | 400 | model is missing. | Pass a model id from GET /v1/models, or auto. |
model_not_found | 404 | No such model on the platform. | Pick one from GET /v1/models. |
messages_required | 400 | messages is missing or empty. | Send at least one message. |
too_many_messages | 400 | More than 256 messages. | Trim the history. |
invalid_request_error | 400 | The model service refused the body: an unsupported role or content part, a tool message without tool_call_id, more than 64 tools, or over 1,000,000 characters of text. | Read message: it names the field. |
query_required | 400 | query is missing or blank. | Send a query. |
query_too_long | 400 | query is over 512 characters (search) or 300 (images). | Shorten it. |
invalid_lane | 400 | lane is not web, fast, deep or auto. | Use one of the four lanes. |
invalid_num_results | 400 | num_results is not a number. | Send an integer from 1 to 25. |
invalid_domains | 400 | include_domains or exclude_domains is not an array of up to 20 host names. | Send arrays of host names. |
queries_required | 400 | queries is missing or empty. | Send an array of query strings. |
batch_too_large | 400 | More queries than your tier's batch size. | Split the batch, or move up a tier. |
invalid_query | 400 | A batch query is blank or over 512 characters. | Fix or drop that query. |
invalid_count | 400 | count is not an integer from 1 to 30. | Send an integer from 1 to 30. |
invalid_reusable | 400 | reusable is not true or false. | Send a boolean. |
unsupported_action | 400 | The maps action is missing or not offered on the API. | Use an action from the Maps table. |
invalid_body | 400 | The mail body is not a JSON object. | Send a JSON object. |
unsupported_field | 400 | Mail got from, cc, bcc, headers or attachments. | Remove the field. Put every recipient in to. |
to_required | 400 | to is missing or empty. | Send an address or a list of them. |
invalid_recipient | 400 | A recipient is not a plain email address. | Send addresses like [email protected], without display names. |
reserved_recipient | 400 | A recipient is on a Kaer sending domain. | Remove it. |
too_many_recipients | 400 | More recipients than your tier allows in one message. | Split the message, or move up a tier. |
subject_required | 400 | subject is missing or blank. | Send a subject. |
subject_too_long | 400 | subject is over 200 characters. | Shorten it. |
body_required | 400 | Neither text nor html was sent. | Send one or both. |
text_too_large | 400 | text is over 128 KB. | Shorten it. |
html_too_large | 400 | html is over 256 KB. | Shorten it. |
invalid_from_name | 400 | from_name is not a string. | Send a string. |
invalid_reply_to | 400 | reply_to is not a plain email address. | Send one address. |
reserved_reply_to | 400 | reply_to is a Kaer address. | Use your own address. |
message_not_found | 404 | No message with that id on this account. | Check the id returned by POST /v1/mail/send. |
Service
| Code | Status | Meaning | What to do |
|---|---|---|---|
upstream_unreachable | 502 | The model service did not answer. Nothing was charged. | Retry with backoff. |
upstream_error | 502 | The model provider failed, or the edge lost its connection to the API. | Retry. After an edge upstream_error the call may already have run. |
model_unavailable | 503 | The model is paused for now. | Use another model, or auto. |
search_failed | 502 | The search service failed. Nothing was charged. | Retry. |
search_busy | 503 | Search is at capacity. Nothing was charged. | Retry in a few seconds. |
search_timeout | 504 | Search ran out of time. Nothing was charged. | Retry, or use a faster lane. |
search_unavailable | 502 or 503 | Search is unreachable or paused. Nothing was charged. | Retry later. |
images_failed | 502 | The picture search failed. Nothing was charged. | Retry. |
images_busy | 503 | Images are at capacity. Nothing was charged. | Retry in a few seconds. |
images_unavailable | 502 or 503 | Images are unreachable, timed out or paused. Nothing was charged. | Retry later. |
maps_unavailable | 502 | The maps service failed. Nothing was charged. | Retry. |
mail_unavailable | 503 | Mail sending is not available. Nothing was charged. | Retry later. |
mail_rejected | 502 | The mail server refused the message. Nothing was charged. | Check the recipients and content. |
mail_transport_failed | 502 | The message could not be handed to the mail server. Nothing was charged. | Retry with a new Idempotency-Key. |
upstream_unavailable | 503 | The API is briefly unreachable from the edge. Sent with Retry-After: 5. | Retry after 5 seconds. |
upstream_timeout | 504 | The edge stopped waiting for an answer. The call may still have run. | Check your usage before you retry. |
Inside a stream
| Code | Status | Meaning | What to do |
|---|---|---|---|
upstream_idle | stream | The model sent nothing for 90 seconds; the stream ends. | Retry, or lower the task's size. |
max_duration | stream | The stream passed 15 minutes; it ends. | Ask for shorter answers, or split the task. |
stream_error | stream | The stream broke on our side. | Retry. |