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

> ## Agent Instructions
> Fetch /llms.txt for the complete page index before exploring further. Every docs page is available as markdown by appending .md to its URL. Coding agents should start at /for-agents/coding-agents.md.

# Errors

> Every Klint error: one compact problem object, what causes each, how to fix it, and whether to retry.

Every non-2xx response is the same compact [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457.html) problem object (`Content-Type: application/problem+json`). Klint trims it to the fields an agent acts on:

```json theme={null}
{
  "type": "https://api.tryklint.ai/problems/validation-failed",
  "status": 422,
  "request_id": "req_example_41",
  "detail": "One request field needs correction.",
  "errors": [
    {
      "pointer": "#/post/filters/format",
      "reason": "INVALID",
      "detail": "Filters must be operator objects, not bare values."
    }
  ]
}
```

| Field        | Meaning                                                                                                                                          |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`       | The absolute URI for this problem type, one URI per type. It resolves to the type's documentation. Branch on this exact string, not on `detail`. |
| `status`     | The HTTP status, repeated in-body                                                                                                                |
| `request_id` | This response's correlation ID, the same one the success envelope returns. Quote it when you report an issue.                                    |
| `detail`     | What happened this time and a safe correction. Human guidance. Do not parse it for control flow.                                                 |

There is no separate `code`, `docs_url`, or `is_retriable` field. The `type` URI is both the identifier you branch on and the link to its docs. Retry guidance lives in the catalog below and in the `Retry-After` header. A `validation-failed` response adds an `errors[]` array. Each entry names the issue's `pointer`, `reason`, and correction. See [what gets rejected](/docs/instagram/search/posts-search#what-gets-rejected) for the canonical examples, including `candidates` suggestions on unknown classification IDs.

## The catalog

Each row's `type` is the absolute URI `https://api.tryklint.ai/problems/<slug>`. The slug shown below is its last path segment and the name the docs use. Branch on the full `type` string.

<Warning>
  The **Retry** column is authoritative; don't infer retryability from the status code. Two `4xx`s below retry differently than their status suggests.
</Warning>

| Problem type              | Status | Retry identical request?           | Notes                                                            |
| ------------------------- | -----: | ---------------------------------- | ---------------------------------------------------------------- |
| `malformed-request`       |    400 | No                                 | Body isn't valid JSON or structurally readable                   |
| `authentication-required` |    401 | No                                 | Fix the key. See [Authentication](/docs/api-reference/authentication) |
| `permission-denied`       |    403 | No                                 | Key lacks access to this operation                               |
| `insufficient-credits`    |    403 | No                                 | Top up, then retry                                               |
| `not-found`               |    404 | No                                 | Malformed or unknown resource key                                |
| `not-tracked`             |    404 | No                                 | Valid key, outside what Klint tracks (see below)                 |
| `method-not-allowed`      |    405 | No                                 |                                                                  |
| `expired-cursor`          |    410 | No, start a new search             | See [pagination](/docs/instagram/search/posts-search#pagination)      |
| `payload-too-large`       |    413 | No                                 | Includes enforced `max_bytes`                                    |
| `unsupported-media-type`  |    415 | No                                 | Send `application/json`                                          |
| `validation-failed`       |    422 | No                                 | Fix the issues in `errors[]`                                     |
| `rate-limit-exceeded`     |    429 | **Yes**, after `Retry-After`       |                                                                  |
| `internal-error`          |    500 | Sometimes, retry once with backoff | Report with the `request_id`                                     |
| `temporarily-unavailable` |    503 | **Yes**, with backoff              |                                                                  |
| `request-timeout`         |    504 | **Yes**, with backoff              |                                                                  |

<Note>
  The catalog may gain types before contract freeze and is deliberately non-exhaustive at the edges. If you hit an undocumented error, report it with its `request_id`.
</Note>

### `not-tracked` deserves a careful read

```json theme={null}
{
  "type": "https://api.tryklint.ai/problems/not-tracked",
  "status": 404,
  "request_id": "req_example_51",
  "detail": "ig_post_7q9zz is a valid Post key but is not in what Klint tracks. This does not claim the post is absent from Instagram."
}
```

It says only that Klint does not track this resource. It never says that the post or account is absent from Instagram. Don't let an agent conclude "this post doesn't exist" from a `not-tracked`.

## Retrying 429s

```json theme={null}
{
  "type": "https://api.tryklint.ai/problems/rate-limit-exceeded",
  "status": 429,
  "request_id": "req_example_53",
  "detail": "Too many requests. Retry after the delay in Retry-After."
}
```

The `Retry-After` header is authoritative. Wait that long. Do not guess:

<CodeGroup>
  ```python Python theme={null}
  import os, time, requests

  def klint_post(url, body, max_attempts=5):
      for attempt in range(max_attempts):
          resp = requests.post(
              url,
              headers={"Authorization": f"Bearer {os.environ['KLINT_API_KEY']}"},
              json=body,
          )
          if resp.status_code != 429:
              return resp
          time.sleep(int(resp.headers.get("Retry-After", 2 ** attempt)))
      return resp
  ```

  ```typescript TypeScript theme={null}
  async function klintPost(url: string, body: unknown, maxAttempts = 5) {
    let resp: Response;
    for (let attempt = 0; attempt < maxAttempts; attempt++) {
      resp = await fetch(url, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.KLINT_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(body),
      });
      if (resp.status !== 429) return resp;
      const wait = Number(resp.headers.get("Retry-After") ?? 2 ** attempt);
      await new Promise((r) => setTimeout(r, wait * 1000));
    }
    return resp!;
  }
  ```
</CodeGroup>

For `503`/`504`, use the same loop with exponential backoff when the response has no `Retry-After` header. Never auto-retry `4xx`s other than `429`. They fail identically until the request changes.

## Across surfaces

The SDK throws one `KlintApiError` that carries the typed problem object. Branch on `problem.type`. MCP tool failures preserve the complete problem object as structured data. The CLI prints a summary and, in JSON mode, writes the exact problem object to stderr. No surface invents its own error dialect.
