Skip to content
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."
}
FieldTypeDescription
errorstringStable snake_case code from the tables below. Switch on this.
messagestringHuman-readable explanation for logs and display. Wording can change.

What to do

The What to do column uses these four actions.

ActionMeaning
Fix the requestThe request is wrong. Sending it again unchanged returns the same error.
Upgrade tierYour tier does not include this. Move to Growth or Enterprise.
Retry after Retry-AfterWait the number of seconds in the Retry-After header, then send the same request.
Retry with backoffTransient 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

CodeReturned byMeaningWhat to doQuota
missing_token
  • All endpoints and /mcp
No Authorization header, or it does not start with Bearer .Fix the request — send Authorization: Bearer uk_live_…Not consumed
invalid_token
  • All endpoints and /mcp
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 keyNot consumed
key_inactive
  • All endpoints and /mcp
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 keyNot consumed

403 Forbidden

CodeReturned byMeaningWhat to doQuota
risk_tier_required
  • /entity/{company_number}/risk
The risk endpoint needs a Growth or Enterprise key.Upgrade tierConsumed
appointments_tier_required
  • /officers/{officer_id}/appointments
Officer appointment history needs a Growth or Enterprise key.Upgrade tierConsumed
control_graph_tier_required
  • /entity/{company_number}/control-graph
The control graph needs a Growth or Enterprise key.Upgrade tierConsumed

404 Not found

CodeReturned byMeaningWhat to doQuota
company_not_found
  • /entity/{company_number}
  • /entity/{company_number}/risk
  • /entity/{company_number}/control-graph
Companies House has no company with this number. The number itself is well formed.Fix the request — check the numberConsumed
officer_not_found
  • /officers/{officer_id}/appointments
Companies House has no officer with this id.Fix the request — check the idConsumed

422 Unprocessable content

CodeReturned byMeaningWhat to doQuota
invalid_company_number
  • /entity/{company_number}
  • /entity/{company_number}/risk
  • /entity/{company_number}/control-graph
The company number is not 1–8 letters and digits. Shorter numbers are zero-padded to 8.Fix the requestConsumed
invalid_sources
  • /entity/{company_number}
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 requestConsumed
land_requires_combination
  • /entity/{company_number}
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,landConsumed
invalid_land_limit
  • /entity/{company_number}
land_limit is not an integer from 1 to 200. Checked after land_requires_combination.Fix the requestConsumed
invalid_query
  • /search
q is missing or shorter than 2 characters after trimming.Fix the requestConsumed
invalid_officer_id
  • /officers/{officer_id}/appointments
The officer id is not 1–64 characters from A-Z a-z 0-9 _ -.Fix the requestConsumed
invalid_control_graph_options
  • /entity/{company_number}/control-graph
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 requestConsumed

429 Too many requests

CodeReturned byMeaningWhat to doQuota
rate_limit_exceeded
  • All endpoints and /mcp
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
  • /entity/{company_number}
  • /entity/{company_number}/risk
  • /officers/{officer_id}/appointments
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 resetRefunded
control_graph_capacity
  • /entity/{company_number}/control-graph
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-AfterConsumed

500 Internal server error

CodeReturned byMeaningWhat to doQuota
internal_error
  • /entity/{company_number}/control-graph
  • /mcp (all tools)
Unexpected failure. Other endpoints can return a 500 without an error field; treat it as internal_error.Retry with backoffConsumed

502 Bad gateway

CodeReturned byMeaningWhat to doQuota
upstream_error
  • /search
  • /officers/{officer_id}/appointments
Companies House returned a server error.Retry with backoffConsumed

503 Service unavailable

CodeReturned byMeaningWhat to doQuota
upstream_unavailable
  • /search
The shared Companies House budget is exhausted, so the search was shed. Unrelated to your quota.Retry after Retry-After — seconds, not your quota resetRefunded

Errors over MCP

  • missing_token, invalid_token, key_inactive and rate_limit_exceeded arrive as HTTP 401 or 429 on the /mcp request, with the shape above.
  • Every other error arrives inside a successful tool result. The result's text content is a JSON object with error and message. Parse it and check for error.
  • Tier errors add current_tier. control_graph_capacity and the search tool's upstream_unavailable add retry_after in 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
}
ToolDifference from REST
get_officer_appointmentsReports a shed lookup as upstream_unavailable, not upstream_capacity, with no retry_after.
search_uk_companiesReports a shed search as upstream_unavailable with retry_after.
lookup_uk_company, get_company_riskReport a shed core lookup as internal_error. Retry with backoff.
lookup_uk_companyReturns 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.