Error Codes
Every error.code, when it happens, and what to do about it.
Branch on error.code. It is stable. message is for humans and may be reworded.
{ "error": { "code": "language_not_found",
"message": "Unknown language code: 'xx-YY'",
"details": { "language": "xx-YY" } } }
Public API
language_not_found — 404
The code matched no canonical code and no alias, and shortening it found nothing either.
Do: log the raw value. Either it is a typo on the sender's side, or it needs an alias here — see Add a new language. If you are classifying rather than resolving, use /v1/normalize, which answers known: false with 200.
Do not retry. The answer will not change until someone edits the catalog.
details.language carries the value you sent.
provider_not_found — 404
No provider code, short name or legacy service_name matched.
Do: check GET /v1/providers for the current list. Legacy console names are registered as aliases, so if a service_name from animated-spoon fails, the provider genuinely does not exist here — see Providers and Vendors.
language_unsupported — 409
Both the provider and the language exist; the pair is recorded as not working.
409 rather than 404 because both named resources are real — it is their combination that is refused, and a caller retrying the same 404 forever would be drawing the wrong conclusion.
Do: pick another provider for that language. GET /v1/languages/{code}/providers shows which ones will take it.
Info
/v1/resolve reports this in the body
The endpoint returns 200 with supported: false and code: null rather than raising, so a caller can log the pair and carry on without exception handling. The 409 form appears where an unsupported pair is a hard failure.
validation_error — 422
The request was malformed: a bad type, a missing parameter, or a batch over 500 pairs.
details.fields lists each problem with its location.
payload_too_large — 413
Body over 256 KB. Split the batch.
internal_error — 500
An unhandled exception. The message is deliberately generic — an unexpected exception may carry a DSN or a row of data, so it goes to the log, not to you.
Do: retry once with backoff, then report it with the X-Correlation-Id from your response headers.
service_unavailable — 503
From /health/ready when the database is unreachable or the catalog is empty (migrations ran, seed did not).
Admin only
| Code | Status | Meaning |
|---|---|---|
unauthorized |
401 | No valid admin session |
csrf_invalid |
403 | Token missing or stale — reload the page |
admin_unavailable |
503 | ADMIN_PASSWORD_HASH / ADMIN_SECRET_KEY not configured |
conflict |
409 | Alias already taken, or deleting a language that still has mappings |
not_found |
404 | Unknown entity |
Next
- Errors and Conventions — response shapes and what is stable