Body/param validation (before the provider is called)
400
invalid_request_error
specific — see table below
Unknown endpoint (path is not a routed inference route, e.g. a typo)
404
invalid_request_error
(none — null)
Unknown / not-allowed model
404 / 403
not_found_error / permission_error
model_not_found / model_not_allowed
Provider-native id requested
404
not_found_error
model_not_found
Deprecated alias past sunset
410
not_found_error
model_deprecated
Image content on non-vision model
400
invalid_request_error
vision_not_supported
Model does not support the endpoint
400
invalid_request_error
unsupported_endpoint
Bad API key
401
authentication_error
invalid_api_key …
Policy denial (allowlists, plan, project)
403
permission_error
specific
Insufficient credit
402
insufficient_quota
insufficient_funds
Gateway rate limit
429 + Retry-After
rate_limit_error
rate_limit_exceeded
Provider 400
400
invalid_request_error
provider_error (verbatim provider message)
Provider 401 / 403
502 (provider detail withheld)
server_error
provider_unavailable
Provider 404 / 5xx
502
server_error
provider_error
Provider 503
503 + Retry-After
server_error
provider_error
Connection failure / no healthy backend
503 + Retry-After
server_error
provider_unavailable
Provider timeout
504 + Retry-After
server_error
provider_unavailable
Body too large
413
invalid_request_error
request_too_large
Streaming failure after first byte
(200 already sent)
in-band record
stream_interrupted / api_key_terminated
Async (video) job failure
200 on poll; status:"failed" in body
—
from the job's error object
Two deliberate design choices:
402 is never 429. A funds denial is not congestion — SDK backoff does
not help and no Retry-After is sent. Full rationale:
Billing.
Provider auth failures never reach you as 401/403. A provider rejecting
our credential is 502 provider_unavailable — the provider's text is
withheld, so you get one clean, actionable error instead of a failure you
could not fix anyway.
Model exists but excluded by your key/project allowlist
403
model_not_allowed
model
Valid model, wrong endpoint for its mode
400
unsupported_endpoint
model
Vision mismatch (image content, non-vision model)
400
vision_not_supported
model
Unknown models return the fused wording "does not exist or you do not have
access to it" — deliberately, so model existence cannot be enumerated. 403 is
returned only where the restriction came from your own configuration.
Generic shape violation (missing messages, negative max_tokens, top_p outside (0, 1] on the completions/responses endpoints, a streaming /v1/completions without stream_options.include_usage: true, non-POST on a JSON endpoint).
invalid_request_body
Body present but not a JSON object.
invalid_stop_sequences
stop has more than 4 entries.
missing_prompt
Image/video generation: prompt absent.
empty_prompt
prompt is empty.
unsupported_response_format
Image response_format:"url" — only b64_json is served.
invalid_image_size
Image size outside the deployment allowlist.
invalid_tool_call_id
role:"tool" message's tool_call_id doesn't match a preceding assistant tool_calls[].id.
vision_not_supported
Image content sent to a non-vision model (param: "model").
invalid_image_url
image_url.url empty or not http/https/data scheme.
unsupported_parameter
A syntactically valid sampling parameter the backend rejects.
unsupported_endpoint
Model's catalogue mode doesn't match the endpoint called (param: "model").
request_too_large
Body over the 8 MiB gateway cap (or the image-specific cap).
This page covers the inference API (https://api.<domain>/v1). The Management API
(https://portal.<domain>/api/v1/mgmt) uses the same envelope family — an error
object with type, code, message, param and request_id — plus an optional
action that says how to fix the problem. Its codes, its status rules and the
type values it uses are listed in Management API errors.
The same rules apply on both surfaces:
Branch on the HTTP status and code. Never parse message; its wording can change.
Every response carries a request id, generated by Token Factory; a request id you
send is ignored. Quote it when you contact support. Where to find it:
Inference API: the X-TF-Request-Id header, repeated as error.request_id
(on /v1/messages, as the top-level request_id).
Portal and Management API: the X-Request-Id header, repeated as
error.request_id.
Codes are stable. New codes can appear, so treat an unknown code as the generic
error for its status.