Errors
Errors are RFC 9457 application/problem+json: type, title, status, optional detail, errors (per-field messages) and instance. Branch on status, and on type for the codes listed below. The table at the bottom of this page is generated from the OpenAPI file and is the complete list.
402: plan, allowance or licence#
When a plan limit, the AI-word allowance or the licence state blocks an action, the API answers 402 with Retry-After where a reset time is known. Permission problems stay 403. The type is urn:resilientlang:problem:<code> like every other API error, and all of these codes are in the generated table at the end of this page.
| Code | Meaning | What to do |
|---|---|---|
site-limit | The plan's site limit is reached | Remove a site or change plan |
language-limit | Too many target languages for the plan | Remove a language or change plan |
ai-words-exhausted | The plan's AI-word allowance is used up | Add a word pack, wait for the period to renew, or bring your own provider key |
quota-exhausted | The AI-word allowance for this period is used up (quota gate); see Retry-After and resetsOn | As above |
machine-translation-disabled | Machine translation is not available because the licence is not active | Renew to translate new strings |
daily-ceiling | Daily translation limit reached | Retry after Retry-After (next UTC day) |
strings-cap | The plan limit on submitted strings is reached | Change plan or wait for the next period |
lapsed-publish-blocked | Publishing is blocked because the plan or licence has lapsed | Renew; published bundles stay live |
licence-inactive | The licence does not allow translate, add a language or publish | Renew; published bundles stay live |
feature-unavailable | The plan does not include this feature | Change plan |
Existing translations and published bundles are never affected by a 402. To see where you stand before you hit a limit, call GET /v1/usage/quota (plan, period, used and remaining words, and a state of ok, soft or exhausted). It answers 404 on a deployment where quotas are not enabled.
Entitlement problems (the plan checks) also carry code, limit, used and remaining as numbers only.
403: suspended account#
account-suspended means the account or site is suspended. Writes are refused; reads and already-published translations keep working. Other 403 types are insufficient-scope (the key lacks the scope shown in the reference), site-restricted-key, origin-not-allowed (discover) and test-key-cannot-issue.
503: a check could not be completed#
gate-unavailable means a plan, quota, licence or suspension check could not run. The API fails closed: it refuses the request rather than letting work through unchecked, and sends Retry-After: 5. Retry shortly. If usage metering cannot write its ledger, translation fails the same way so usage is never silently lost.
service-unavailable means the service could not reach its database (or the call timed out) and nothing was changed. Public pages and published bundles keep working. The API answers 503 with Retry-After: 30; retry after that many seconds.
In the SDKs#
The Python, PHP and Go SDKs expose these fields and a hint for 402, 403 and 503: see SDK error handling.
Rate limits and idempotency#
429 carries Retry-After. A repeated write with the same Idempotency-Key returns the stored response with Idempotent-Replayed: true; the same key with a different request is 422; the same key while the first request is still running is 409.
Problem types in the control-plane API#
Generated from the x-problem-types list in openapi.json:
| Status | Type | Meaning |
|---|---|---|
400 | urn:resilientlang:problem:validation | One or more fields are invalid; see errors{field: [messages]}. |
400 | urn:resilientlang:problem:bad-json | The body is not valid JSON for this endpoint. |
400 | urn:resilientlang:problem:bad-request | Malformed request (missing body, malformed multipart, too many parts). |
400 | urn:resilientlang:problem:no-allowed-origins | The site has no allowed origins, so it cannot be scanned. |
400 | urn:resilientlang:problem:import-format | The uploaded file could not be read (malformed, not UTF-8, DTD, over limits). |
401 | urn:resilientlang:problem:unauthorized | Missing, malformed, unknown, expired or revoked secret key. |
403 | urn:resilientlang:problem:insufficient-scope | The key lacks the scope this endpoint requires. |
403 | urn:resilientlang:problem:account-suspended | The account or site is suspended: writes are refused, reads and already-published translations keep working. |
403 | urn:resilientlang:problem:site-restricted-key | The key is restricted to one site and cannot do this. |
403 | urn:resilientlang:problem:origin-not-allowed | Discover: unknown site key or the request Origin is not allowed. |
403 | urn:resilientlang:problem:test-key-cannot-issue | Test keys cannot create keys. |
404 | urn:resilientlang:problem:not-found | The resource does not exist or is not accessible with this key. |
405 | urn:resilientlang:problem:method-not-allowed | Wrong HTTP method for the path. |
402 | urn:resilientlang:problem:quota-exhausted | The AI-word allowance for this period is used up. See Retry-After and resetsOn; add a word pack or bring your own provider key. |
402 | urn:resilientlang:problem:machine-translation-disabled | Machine translation is not available (licence not active). |
402 | urn:resilientlang:problem:daily-ceiling | Daily translation limit reached; retry after Retry-After. |
402 | urn:resilientlang:problem:strings-cap | The plan limit on submitted strings is reached. |
402 | urn:resilientlang:problem:site-limit | The plan allows no more sites. |
402 | urn:resilientlang:problem:language-limit | The plan allows no more target languages. |
402 | urn:resilientlang:problem:ai-words-exhausted | The plan's AI-word allowance is exhausted. |
402 | urn:resilientlang:problem:lapsed-publish-blocked | Publishing is blocked because the plan or licence has lapsed. |
402 | urn:resilientlang:problem:feature-unavailable | The plan does not include this feature. |
402 | urn:resilientlang:problem:licence-inactive | The licence does not allow this action (translate, add_language, publish); already-published bundles keep being served. |
409 | urn:resilientlang:problem:idempotency-in-flight | A request with the same Idempotency-Key is still running; retry after Retry-After. |
413 | urn:resilientlang:problem:payload-too-large | The body or file exceeds the limit. |
415 | urn:resilientlang:problem:unsupported-media-type | Use application/json (or multipart/form-data for import). |
422 | urn:resilientlang:problem:idempotency-key-reused | The Idempotency-Key was used with a different request. |
422 | urn:resilientlang:problem:import-rejected | The import has errors; nothing was written. See issues[]. |
429 | urn:resilientlang:problem:rate-limited | Too many requests; wait Retry-After seconds. |
429 | urn:resilientlang:problem:limit-reached | A hard abuse ceiling that does not depend on the plan was reached (for example the number of source strings one site may hold, ResilientLang:Limits:MaxStringsPerSite). |
503 | urn:resilientlang:problem:gate-unavailable | A plan, quota, licence or suspension check could not be completed (fails closed); retry after Retry-After. |
503 | urn:resilientlang:problem:service-unavailable | The service could not reach its database (or it timed out); nothing was changed. Retry after Retry-After. |
500 | urn:resilientlang:problem:internal | Unexpected error; quote the reference in detail when reporting it. |