Browse documentation
Error codes
Every error response has a stable error code and a human-readable message. Build your logic on error, not on message.
Response shape
{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded. Try again later."
}| Field | Type | Description |
|---|---|---|
error | string | Stable snake_case code from the tables below. Switch on this. |
message | string | Human-readable explanation for logs and display. Wording can change. |
What to do
The What to do column uses these four actions.
| Action | Meaning |
|---|---|
| Fix the request | The request is wrong. Sending it again unchanged returns the same error. |
| Upgrade tier | Your tier does not include this. Move to Growth or Enterprise. |
Retry after Retry-After | Wait the number of seconds in the Retry-After header, then send the same request. |
| Retry with backoff | Transient failure. Retry with exponential backoff and a retry limit. |
The Quota column describes REST requests. Over MCP every tool call is consumed, including errors, except get_account_status, which is never counted. See request cost.
Codes
401 Unauthorised
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| missing_token |
| No Authorization header, or it does not start with Bearer . | Fix the request — send Authorization: Bearer uk_live_… | Not consumed |
| invalid_token |
| The token matches no API key. Over MCP, the OAuth access token is invalid, expired or not scoped for MCP. | Fix the request — check the key | Not consumed |
| key_inactive |
| The key exists but is deactivated, for example because you regenerated it. Over MCP with OAuth, your account has no active key. | Fix the request — use your current key | Not consumed |
403 Forbidden
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| risk_tier_required |
| The risk endpoint needs a Growth or Enterprise key. | Upgrade tier | Consumed |
| appointments_tier_required |
| Officer appointment history needs a Growth or Enterprise key. | Upgrade tier | Consumed |
| control_graph_tier_required |
| The control graph needs a Growth or Enterprise key. | Upgrade tier | Consumed |
404 Not found
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| company_not_found |
| Companies House has no company with this number. The number itself is well formed. | Fix the request — check the number | Consumed |
| officer_not_found |
| Companies House has no officer with this id. | Fix the request — check the id | Consumed |
422 Unprocessable content
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| invalid_company_number |
| The company number is not 1–8 letters and digits. Shorter numbers are zero-padded to 8. | Fix the request | Consumed |
| invalid_sources |
| sources contains an unknown value, is empty, or names only sources your tier cannot use. For an unknown or empty value, the message lists the sources that are currently available. | Fix the request | Consumed |
| land_requires_combination |
| land is the only source left after tier filtering. Land Registry data is never returned on its own. | Fix the request — add a source, e.g. ?sources=ch,land | Consumed |
| invalid_land_limit |
| land_limit is not an integer from 1 to 200. Checked after land_requires_combination. | Fix the request | Consumed |
| invalid_query |
| q is missing or shorter than 2 characters after trimming. | Fix the request | Consumed |
| invalid_officer_id |
| The officer id is not 1–64 characters from A-Z a-z 0-9 _ -. | Fix the request | Consumed |
| invalid_control_graph_options |
| direction is not ancestors or group, or max_depth or max_nodes is not an integer from 1 to your tier's maximum. | Fix the request | Consumed |
429 Too many requests
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| rate_limit_exceeded |
| Your account's monthly quota is used up. | Retry after Retry-After — at the end of your quota window. Or Upgrade tier. | Already spent |
| upstream_capacity |
| The shared Companies House budget is exhausted, so the core lookup was shed. Unrelated to your quota. | Retry after Retry-After — seconds, not your quota reset | Refunded |
| control_graph_capacity |
| A graph could not start: another graph is running on your account, both platform graph slots are busy, your graph admission allowance is empty, or the subject lookup was shed. | Retry after Retry-After | Consumed |
500 Internal server error
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| internal_error |
| Unexpected failure. Other endpoints can return a 500 without an error field; treat it as internal_error. | Retry with backoff | Consumed |
502 Bad gateway
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| upstream_error |
| Companies House returned a server error. | Retry with backoff | Consumed |
503 Service unavailable
| Code | Returned by | Meaning | What to do | Quota |
|---|---|---|---|---|
| upstream_unavailable |
| The shared Companies House budget is exhausted, so the search was shed. Unrelated to your quota. | Retry after Retry-After — seconds, not your quota reset | Refunded |
Errors over MCP
missing_token,invalid_token,key_inactiveandrate_limit_exceededarrive as HTTP401or429on the/mcprequest, with the shape above.- Every other error arrives inside a successful tool result. The result's text content is a JSON object with
errorandmessage. Parse it and check forerror. - Tier errors add
current_tier.control_graph_capacityand the search tool'supstream_unavailableaddretry_afterin seconds, in place of the header. - Codes otherwise match REST, except for the cases below.
{
"error": "control_graph_capacity",
"message": "Control graph capacity reached. Please retry shortly.",
"retry_after": 10
}| Tool | Difference from REST |
|---|---|
get_officer_appointments | Reports a shed lookup as upstream_unavailable, not upstream_capacity, with no retry_after. |
search_uk_companies | Reports a shed search as upstream_unavailable with retry_after. |
lookup_uk_company, get_company_risk | Report a shed core lookup as internal_error. Retry with backoff. |
lookup_uk_company | Returns validation_failed when an optional argument such as include_resigned has the wrong type. |
Related
A 200 with entries in sources_failed is a partial response, not an error: see Interpreting risk signals. For why there are three kinds of 429, see Capacity and quotas.