Skip to content

Chat Completions API errors

POST /v1/chat/completions returns errors in OpenAI’s Chat Completions error envelope. Errors that originate at Kindo’s edge use the table below; errors that originate upstream are forwarded verbatim with the upstream body and content-type.

Envelope

{
"error": {
"message": "Model 'unknown-model' not found.",
"type": "invalid_request_error",
"code": "model_not_found"
}
}

Status / type / code reference

StatusTypeCommon codesCause
400invalid_request_errorinvalid_body, model_not_foundBody fails schema validation or references a missing model.
401Missing/malformed/revoked key. Plain envelope: {"error": "Unauthorized"}.
403permission_errormodel_access_deniedThe key authenticated, but the user group does not grant access.
429rate_limit_errorOrg or user rate limit. Honors Retry-After when present.
500server_errorinternal_errorUnexpected Kindo-side failure.
502server_errorupstream_empty_bodyUpstream returned an empty body.

Chat Completions does not emit 404 from Kindo’s edge — any 404 the client sees is upstream provider passthrough.

401 exception

401 uses the plain-string envelope {"error": "Unauthorized"} rather than the typed {"error": {"message": "...", ...}} shape. This matches Kindo’s API-key middleware on /v1/chat/completions and /v1/responses.

Mid-stream errors

Once stream: true has flipped the response into SSE, errors arrive as an inline event: error SSE frame followed by data: [DONE]:

event: error
data: {"error":{"message":"upstream stream interrupted","type":"server_error","code":"stream_error"}}
data: [DONE]

Treat any event: error payload with code: "stream_error" as terminal. The outer HTTP status stays 200.

Provider passthrough

When LiteLLM or the upstream provider returns a 4xx or 5xx with its own body, Kindo forwards that body verbatim (preserving the upstream Content-Type) so your client sees whatever shape the upstream produced. Kindo does not rewrap. The exception is upstream_empty_body, which Kindo emits when the upstream returned an HTTP error with no body so consumers always have a parseable JSON envelope.

If you want a single consistent error shape across providers, parse on the outer HTTP status first; only fall back to body inspection when you need provider-specific detail.

See also