Errors
Errors use the OpenAI envelope:
{ "error": { "message": "…", "type": "insufficient_quota", "code": "insufficient_quota", "param": null } }Branch on code. The message is for people and may change. Every response, success or error, has an x-katara-request-id header; include it when you write to support.
| HTTP | code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request | The body is malformed. | Fix the request. |
| 400 | feature_not_supported | The model does not support what the request asks for: tools, structured output, reasoning, a tool_choice outside its contract, or a parameter it does not act on (param names the field). A parameter left at its default is accepted and dropped. | Check capabilities, tool_contract and supported_params on /v1/models. |
| 401 | invalid_api_key | Missing or unknown key. | Create a key in the portal. |
| 403 | account_suspended | The account behind the key is suspended. | Contact support. |
| 404 | model_not_found | Unknown model id. | Use an id from /v1/models. |
| 429 | insufficient_quota | Spendable balance is below the request’s maximum cost. | Add USDC, raise the budget cap, or lower max_tokens. Honour Retry-After. |
| 502 | provider_output_invalid | Every provider tried answered with something Katara refused to deliver: a reply with no text and no tool call, a malformed tool call, tool syntax left in the text, a runtime fault, a reply stuck repeating itself, or a stop the runtime did not mean. Managed models are held to the same rule. Nothing was charged. | Retry after Retry-After; for tool calls, ask for a smaller output. |
| 502 | provider_rejected_request | Every provider tried refused the request body itself: a conversation history its runtime will not render, or a field it cannot take. Nothing was charged and a retry of the same request will fail the same way. | Check the history and parameters, then send a corrected request. |
| 503 | no_capacity | No provider can serve the named model right now; for katara/cortex@1, no candidate could. A named model is never substituted. | Retry after Retry-After, or ask katara/cortex@1. |
| 500 | internal_error | Something failed on our side. | Retry; report the request id if it persists. |
Streams
Section titled “Streams”A stream that fails after content was sent ends with an error chunk, then [DONE]:
data: {"error":{"message":"stream interrupted by provider failure; delivered tokens are not billed without a verified receipt","type":"server_error","code":"stream_interrupted"}}Two codes can appear there. stream_interrupted means the provider stopped or disconnected. provider_output_invalid means the provider’s reply failed validation, for example a tool call that could not be delivered, a reply that kept repeating itself, or a reply that ended with nothing delivered. In both cases nothing is charged for that attempt. Send the request again.
A reasoning model’s thinking arrives under reasoning_content in the message or the delta, before the answer. It is shown, never counted as the answer: a reply that only reasoned and never answered is refused like an empty one.
Wallet-paid requests
Section titled “Wallet-paid requests”A request paid per call is bound to the provider quoted in its 402 challenge. If that provider fails before delivering anything, a named model answers 502 provider_failed and nothing is charged; request a new challenge. For katara/cortex@1 the answer is a fresh 402 for the next candidate: sign it and retry, the first authorization expires unused.