Skip to main content

Errors and rate limits

/ API docs

← API quickstartView as Markdown

Errors come back as an HTTP status with a JSON body in the format of the endpoint you called. Every message starts with 🧀, so you can tell an OpenCheese message from the model's text, and every response carries an x-request-id header: quote it when you contact support.

Error shapes

OpenAI endpoints (/v1/chat/completions, /v1/responses, /v1/images/*, /v1/models and the account endpoints):

json
{
  "error": {
    "message": "🧀 Invalid or disabled OpenCheese API key.",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}

The Anthropic endpoint (/v1/messages) wraps the same fields in Anthropic's envelope:

json
{
  "type": "error",
  "error": {
    "message": "🧀 Invalid or disabled OpenCheese API key.",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}

Errors worth waiting for add retry_after (seconds) to the body and a Retry-After header.

Errors after a stream has started

Once a streaming answer has begun, the HTTP status is already 200, so a failure arrives in the stream:

  • /v1/chat/completions: the message arrives as assistant text, then a final chunk and data: [DONE].
  • /v1/responses: a response.failed event, with response.error.code and response.error.message.
  • /v1/messages: an error event with the Anthropic error object.

Chat Completions answers some errors as a reply

On /v1/chat/completions, problems you need to act on arrive as the assistant's reply, in a 200 response streamed as text/event-stream, even when stream is false:

text
data: {"object":"chat.completion.chunk","model":"opencheese","choices":[{"index":0,"delta":{"role":"assistant","content":"🧀 Invalid or disabled OpenCheese API key."},"finish_reason":"stop"}]}

data: [DONE]

That covers an invalid or disabled key, a blocked account, an invalid session header, a body that is not a valid request, a request the content policy blocks, and every balance or plan limit. Chat apps show the message to you that way. In your own code, check the Content-Type: text/event-stream on a non-streaming request means the reply is such a message. Every other error on this endpoint is a normal status with a JSON body.

Codes

Code Status What happened Retry?
invalid_api_key 401 The key is wrong, revoked or disabled. No
account_banned, account_frozen, account_disabled 403 The account cannot make requests; the dashboard says why. No
invalid_request_error 400 The body is not a valid request for this endpoint. No
invalid_session_header 400 opencheese-session-uuid is not a valid id; see Sessions. No
model_not_found 404 No model has this ID. Read /v1/models. No
model_access_denied 403 The model is switched off on your Prices page, or the key's model list leaves it out. No
model_disabled, model_pricing_disabled 400 The model is not offered right now. No
unsupported_model 400 Wrong endpoint for the model, such as a text model on /v1/images/generations. No
streaming_unsupported 400 The model does not stream; send the request without stream. No
unsupported_reasoning_effort 400 The model has no such effort level; supported_reasoning_levels lists its levels. No
context_length_exceeded 400 The prompt is longer than the model's context window. No
request_blocked_by_guard 403 The content policy blocked the request. No
provider_refusal 400 The model declined to answer. Only with a changed request
moderation_blocked, moderation_blocked_billed 400 The model's content policy declined the prompt or the image. Only with a changed request
plan_limit_reached 429 The balance, a plan window, a key's spending cap or a monthly limit is used up, or the model is outside your plan. After it resets or you top up
rate_limit_exceeded 429 Too many requests; see below. After Retry-After
requested_effort_unavailable 429 The effort level is temporarily unavailable; the error lists the other levels. After Retry-After, or another level
provider_unavailable 429 The model is temporarily unavailable. After Retry-After
provider_overloaded 5xx The model is overloaded. Yes, with backoff, or another model
request_timeout 504 The answer took too long. Yes
service_unavailable 503 The gateway is briefly busy. Yes, shortly

On /v1/chat/completions, the errors that arrive as a reply (see above) come with status 200 instead of the one shown here.

On /v1/messages, plan_limit_reached also sends x-should-retry: false, so the Anthropic SDKs do not resend it.

An effort the model does not offer

json
{
  "error": {
    "message": "🧀 Example Model is not available for Ultra effort. Choose one of these efforts: low, medium, high.",
    "type": "invalid_request_error",
    "code": "unsupported_reasoning_effort",
    "supported_reasoning_levels": ["low", "medium", "high"]
  }
}

The levels run from the weakest to the strongest and are the same ones /v1/models lists for the model. A model without levels answers that it takes no effort setting: leave the field out. If you don't send an effort at all, the model's default is used and this error never occurs.

Rate limits

Each account has request limits per minute, hour, day and month. A request over a limit is answered 429 rate_limit_exceeded with these headers:

Header Meaning
Retry-After Seconds until you may try again.
x-ratelimit-limit The limit you reached.
x-ratelimit-remaining 0.
x-ratelimit-reset When the window resets, as an ISO 8601 time.

A very short burst of requests can also answer 429 without these headers: wait a few seconds before retrying. The account endpoints (/v1/key, /v1/plan, /v1/balance) and /v1/messages/count_tokens do not count toward the limits.

Retrying

  • Retry 429, 5xx and request_timeout, honouring Retry-After when it is present, with exponential backoff otherwise.
  • Do not retry 400, 401, 403 and 404 unchanged: the same request fails the same way.
  • plan_limit_reached clears when the window resets, when you top up, or when you switch on Use balance for Credit Models on the dashboard's Overview.

Notices next to an answer

A successful answer can carry opencheese_notifications, a list of notices about your account, such as a plan window that is about to run out. They do not change the answer.

The cheese has holes. Your infrastructure should not.