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

# Errors

> The error envelope and the stable set of codes your client should branch on.

Every non-2xx response uses a single, consistent envelope:

```json theme={null}
{
  "error": {
    "code": "not_found",
    "message": "The requested resource was not found."
  }
}
```

* `code` is a **machine-readable** value from the fixed set below — branch your logic on it.
* `message` is a human-readable explanation. It may change over time; **never** parse or
  switch on it.

## Error codes

The set of codes is closed and stable — new codes are added rarely and announced.

| Code              | HTTP        | When                                                                                                                |
| ----------------- | ----------- | ------------------------------------------------------------------------------------------------------------------- |
| `invalid_request` | `400`       | A malformed or invalid path, query, or body parameter (including a bad `cursor` or an offset-less `updated_since`). |
| `unauthorized`    | `401`       | Missing, malformed, invalid, or revoked API key.                                                                    |
| `not_found`       | `404`       | Unknown resource, a resource outside your entitlements, or no such route.                                           |
| `rate_limited`    | `429`       | Per-minute rate limit exhausted. Carries a `Retry-After` header.                                                    |
| `request_failed`  | `4xx`/`5xx` | Catch-all for an otherwise-unclassified request failure.                                                            |
| `internal_error`  | `500`       | An unexpected server error. Retry later; if it persists, contact support.                                           |

<Note>
  Entitlement boundaries are enforced as `404`, not `403`: a resource your key isn't
  entitled to is indistinguishable from one that doesn't exist, so existence is never
  leaked across organizations.
</Note>

## Handling errors

Switch on `error.code` and treat the HTTP status as a coarse category:

```python theme={null}
resp = requests.get(url, headers=headers)
if resp.status_code == 429:
    wait = int(resp.headers.get("Retry-After", "1"))
    # back off for `wait` seconds, then retry
elif not resp.ok:
    code = resp.json()["error"]["code"]
    # branch on `code` — e.g. refresh credentials on "unauthorized"
```
