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

# Limits and errors

> Every cap, every issue code, and exactly what happens when you cross one.

Our rule is **show, never silently drop**. When part of your content is still useful, we trim it and say so. When the shape is wrong, we reject it loudly. Nothing ever disappears without a note in your delivery log.

## Limits

| Limit                          | Value       | What happens                                |
| ------------------------------ | ----------- | ------------------------------------------- |
| Payload size                   | 256 KB      | Rejected — `PAYLOAD_TOO_LARGE` (HTTP `413`) |
| Messages per call              | 10          | Rejected — `TOO_MANY_MESSAGES`              |
| Blocks per message             | 25          | Trimmed, plus a visible "+N more" block     |
| Characters per `text` block    | 12,000      | Trimmed, with a visible note                |
| Buttons per `button_group`     | 5           | Block removed — `BUTTONS_TOO_MANY`          |
| Buttons per `card`             | 3           | Block removed                               |
| Interactive blocks per message | 5           | Extras removed                              |
| Forms per message              | 1           | Extras removed — `FORM_EXCLUSIVITY`         |
| Fields per form                | 10          | Block removed                               |
| Options per select             | 50          | Block removed                               |
| Cards per message              | 5           | Extras removed                              |
| Button `value` length          | 2,000 chars | Button removed                              |
| Message `metadata`             | 2 KB        | Metadata removed; blocks still show         |
| URL length                     | 2,048 chars | Block removed                               |
| Updates per message            | 60          | `429 UPDATE_LIMIT_REACHED`                  |
| Response URL lifetime          | 45 minutes  | `410 RESPONSE_URL_EXPIRED`                  |
| Image upload                   | 10 MB       | `413 FILE_TOO_LARGE`                        |
| File upload                    | 25 MB       | `413 FILE_TOO_LARGE`                        |

## Two kinds of failure

<Steps>
  <Step title="Tier 1 — the whole payload is rejected">
    Nothing shows. The whole body is wrong: not JSON, an unknown shape, a bad version, too big, or too many messages. You get a `422` (or `413`).
  </Step>

  <Step title="Tier 2 — one block is wrong">
    The message still goes through. The bad block shows as a small placeholder in the app, and is skipped on public pages. Everything else draws as normal.
  </Step>
</Steps>

That split is on purpose: one bad button should never cost your customer the whole answer.

## The error body

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "BLOCK_VALIDATION_FAILED",
    "message": "2 issue(s) found in your Block Kit payload.",
    "issues": [
      {
        "code": "BUTTONS_TOO_MANY",
        "path": "/messages/0/blocks/1/buttons",
        "message": "Max 5 buttons per button_group (got 8).",
        "severity": "error",
        "limit": 5,
        "actual": 8
      },
      {
        "code": "INSECURE_URL",
        "path": "/messages/0/blocks/2/url",
        "message": "URLs must use https:// (got http://).",
        "severity": "error"
      }
    ]
  }
}
```

<ResponseField name="path" type="string">
  A JSON Pointer into the **cleaned-up** payload. If you used shortcuts, the numbers may not match your raw body.
</ResponseField>

<ResponseField name="severity" type="string">
  `error` removes the block, `warning` changes it visibly, `info` is just a note.
</ResponseField>

<ResponseField name="limit" type="number">
  The cap, on limit issues.
</ResponseField>

<ResponseField name="actual" type="number">
  What you sent.
</ResponseField>

Every other failure uses the same wrapper, without `issues`:

```json theme={null}
{ "ok": false, "error": { "code": "conversation_taken_over", "message": "An operator has taken over this conversation." } }
```

<Tip>
  Ignoring HTTP responses in Make or n8n? The same issues show in your bot's delivery log, so you can still find out why nothing appeared.
</Tip>

## Issue codes

### Rejects the whole payload

| Code                            | Meaning                                                       |
| ------------------------------- | ------------------------------------------------------------- |
| `UNRECOGNIZED_ENVELOPE`         | Not a shape we accept. The message lists every shape we take. |
| `BLOCK_KIT_VERSION_UNSUPPORTED` | `block_kit_version` was not `"1"`.                            |
| `PAYLOAD_TOO_LARGE`             | Over 256 KB.                                                  |
| `TOO_MANY_MESSAGES`             | Over 10 messages — usually a loop bug in a scenario.          |

### Removes one block

| Code                          | Meaning                                                    |
| ----------------------------- | ---------------------------------------------------------- |
| `MISSING_REQUIRED_FIELD`      | A needed field is missing, or the block failed its schema. |
| `INVALID_MESSAGE`             | Not a message or block shape we recognize.                 |
| `FORM_EXCLUSIVITY`            | More than one form, or a form next to a `button_group`.    |
| `BUTTONS_TOO_MANY`            | Over 5 in one `button_group`.                              |
| `INTERACTIVE_BLOCKS_TOO_MANY` | Over 5 interactive blocks, or over 5 cards.                |
| `FORM_FIELDS_TOO_MANY`        | Over 10 fields.                                            |
| `OPTIONS_TOO_MANY`            | Over 50 select options.                                    |
| `DUPLICATE_ACTION_ID`         | Two buttons share an `action_id` in one message.           |
| `DUPLICATE_FIELD_NAME`        | Two fields share a `name`, or two forms share a `form_id`. |
| `VALUE_TOO_LONG`              | Button `value` over 2,000 characters.                      |
| `URL_TOO_LONG`                | Over 2,048 characters.                                     |
| `INSECURE_URL`                | Not `https://`.                                            |
| `FIELD_TOO_LONG`              | A `mid` that breaks `^[a-zA-Z0-9_.:-]{1,64}$`.             |

### Warnings — it still goes through

| Code                      | Meaning                                                                   |
| ------------------------- | ------------------------------------------------------------------------- |
| `BLOCKS_TRUNCATED`        | Over 25 blocks. First 25 kept, plus a note.                               |
| `TEXT_TRUNCATED`          | Over 12,000 characters. Cut, with a visible ending.                       |
| `METADATA_TOO_LARGE`      | Over 2 KB. Metadata removed, blocks kept.                                 |
| `UNKNOWN_BLOCK_TYPE`      | A `type` we do not know. Placeholder in the app, skipped on public pages. |
| `suppressed_default_body` | You returned `Accepted`, `OK`, or similar.                                |

### Notes

| Code                     | Meaning                                              |
| ------------------------ | ---------------------------------------------------- |
| `PROGRESS_CLAMPED`       | A `statusprogress` outside 0–100 was pulled back in. |
| `unknown_fields_dropped` | Fields we do not know were removed.                  |
| `ack_no_message`         | Empty body or `{}` — got it, nothing created.        |

## HTTP status codes

| Status | Codes                                                                                  |
| ------ | -------------------------------------------------------------------------------------- |
| `400`  | `MALFORMED_MULTIPART`, `AMBIGUOUS_UPDATE_TARGET`                                       |
| `401`  | `token_invalid`, `invalid_api_key`                                                     |
| `402`  | `MESSAGE_CAP_REACHED`, `STORAGE_CAP_REACHED`                                           |
| `403`  | `not_bot_authored`, `wrong_chatbot`                                                    |
| `404`  | `conversation_not_found`, `message_not_found`                                          |
| `409`  | `conversation_taken_over`                                                              |
| `410`  | `RESPONSE_URL_EXPIRED`                                                                 |
| `413`  | `PAYLOAD_TOO_LARGE`, `FILE_TOO_LARGE`                                                  |
| `415`  | `IMAGE_FORMAT_UNSUPPORTED`                                                             |
| `422`  | `BLOCK_VALIDATION_FAILED`, `EMPTY_BODY`, `FRAMEWORK_DEFAULT_BODY`, `FILE_TYPE_BLOCKED` |
| `429`  | `rate_limited`, `UPDATE_LIMIT_REACHED`                                                 |
| `500`  | `PERSIST_FAILED`, `UPLOAD_FAILED`                                                      |

<Note>
  A `429` includes `retry_after` in seconds. Wait that long instead of hammering.
</Note>
