> ## Documentation Index
> Fetch the complete documentation index at: https://docs.utmkit.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Every refusal comes back in one envelope, with a code from a closed list and a sentence a person can read.

The API never answers a refusal with a bare status. Every one carries the same envelope:

```json theme={null}
{
  "error": {
    "code": "governance_refused",
    "message": "utm_source must be lowercase: Newsletter → newsletter."
  }
}
```

`code` and `message` are always there. One of `details`, `permission` or
`retry_after_seconds` is added when it applies.

* `code` is one word from a closed list, for your program to branch on.
* `message` is one sentence, for a person to read. It is the same sentence the console
  shows for the same refusal, so a marketer and an integrator looking at the same problem
  see the same words.
* `details` appears on `invalid_input`: a map of field name to a list of messages when the
  workspace's own validation refused, or of JSON pointer (`/destination`) to one message
  when the request failed schema validation.
* `permission` appears on `missing_permission`: the permission the token lacks.
* `retry_after_seconds` appears on `rate_limited`, and on the hourly `limit_reached`.

## The codes

The list lives in the `Error` schema of the API reference, and that schema is generated
from the API itself, so it is always current. In outline, the codes fall into four
families:

* **The door** — `unauthenticated` (401), `subscription_required` and
  `subscription_ended` (402), `missing_permission` and `role_forbids` (403),
  `rate_limited` (429). See [Authentication & tokens](/en/developers/authentication) and
  [Rate limits](/en/developers/rate-limits).
* **The plan** — `plan_forbids` (403) when the plan does not include the feature,
  `limit_reached` (429) when one of the two abuse bounds on the
  [Rate limits](/en/developers/rate-limits) page is hit, with `Retry-After` only for the
  hourly one. A report window the plan does not reach is `invalid_input` (422), below.
* **The rules** — `governance_refused` when the workspace's convention, approved values
  or dependency rules refuse the input, `scanner_refused` when the destination failed the
  safety scan, `duplicate_link` when the workspace already has a link with exactly that
  tagged destination (409, the only conflict in the set: the message names the existing
  link, and the right move is to use it rather than retry). The first two are 422.
* **The request** — `invalid_input` (422) with `details`, and `not_found` (404). A
  resource of another workspace and one that does not exist are the same answer, on
  purpose.

## How the MCP server reports the same things

A tool call never returns this envelope. A refusal is a **tool result** flagged as an
error, whose text is the `message` above, so the assistant can relay it or repair the
input. A protocol-level error means the client spoke wrongly; a refusal means the product
said no. The door's refusals (401, 402, 429) do apply to the MCP server, and they fail the
connection with that HTTP status rather than a tool result, because a token that is not
admitted has no tools to list.
