{
  "schema_version": 2,
  "id": "develop/ai/context-engine/agent-playbooks/limits",
  "title": "Service limits and errors",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/limits/",
  "summary": "Find content and retrieval limits, proposal retention, error types, and retry guidance.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-11-02T15:54:35-08:00",
  "page_type": "content",
  "content_hash": "ee66adb296f5e9056bfca3e9619d9d6e267b77f10a9a1660838ec4e328570cbf",
  "sections": [
    {
      "id": "code-examples",
      "title": "Code examples",
      "role": "example",
      "text": "These examples connect to Iris services using SDKs or HTTP requests with curl. Follow one language throughout each walkthrough.\n\n\nCheck these limits when preparing content or handling request failures. Confirm deployment overrides with your administrator.\n\nThe [API reference](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/api-reference) defines field formats and operation-specific schemas."
    },
    {
      "id": "content-limits",
      "title": "Content limits",
      "role": "content",
      "text": "These defaults can be lower in your deployment. Byte limits apply to decoded content, not base64 length. A kibibyte (KiB) is 1,024 bytes; a mebibyte (MiB) is 1,024 KiB.\n\n| Content | Default ceiling |\n|:--------|:----------------|\n| Entries per playbook | 10,000 |\n| Versions per entry | 100 |\n| Retained content across an entry's versions | 256 MiB |\n| Files per skill version, including `SKILL.md` | 64 |\n| ZIP archive entries, including directories | 256 |\n| Compressed skill archive | 5 MiB |\n| Expanded skill archive | 20 MiB |\n| Individual skill file | 5 MiB |\n| Skill instructions file (`SKILL.md`) | 1 MiB |\n| Version metadata | 64 KiB, nesting depth 16 |\n\nRetained data includes version content and resources. Withdrawal does not free capacity; deletion removes the entry's history. You cannot delete an individual version.\n\nThese field and structure limits also apply:\n\n| Field or structure | Limit |\n|:-------------------|:------|\n| FAQ question | 2,048 characters |\n| FAQ answer | 32,768 characters |\n| Intents | Five per entry version; 2,048 characters each |\n| Attributes | 32 names; up to 20 scalar items in each list value |\n| Entry key or skill name | 64 characters |\n| Skill description | 1,024 characters |\n| Skill compatibility text | 500 characters |"
    },
    {
      "id": "retrieval-limits",
      "title": "Retrieval limits",
      "role": "content",
      "text": "| Request or setting | Limit or default |\n|:-------------------|:-----------------|\n| Search or discovery query | 1–4,096 characters |\n| Type-specific search results | 1–50; omission uses the playbook's result default |\n| Discovery results | 1–50, bounded by `discovery.maxResults`; service default `10`, unified Python helper default `5` |\n| Similarity thresholds | `0`–`1`; default `0.7` for each entry type |\n| Discovery preview ceiling | Disabled by default; minimum configured value `64` estimated tokens |\n| Filter depth | Five |\n| Equality predicates in a filter | 64 |\n| Management list page | 1–200 results; default `50` |\n| Entry lookup or bulk deletion | 1–100 entry references or identifiers |\n\nPins consume discovery slots and preview budget. The preview ceiling applies to discovery rather than type-specific search, loaded instructions, or fetched files. See [Retrieve knowledge](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/retrieval) for the behavior of each setting.\n\nFollow a list response's next cursor until it is absent, even if a page is empty. Keep the collection, filters, and ordering consistent between pages. Lists reflect concurrent changes and do not represent a fixed snapshot.\n\nList responses return `items` and `nextCursor` and do not include a total count. Use the cursor, not the page length, to decide when to stop. For separate observed counts, use `get_playbook_stats`; an unavailable count is not zero. See [List entries and inspect history](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-faqs#list-entries-and-inspect-history) for examples."
    },
    {
      "id": "proposal-and-evidence-limits",
      "title": "Proposal and evidence limits",
      "role": "content",
      "text": "| Limit or policy | Value |\n|:----------------|:------|\n| Open proposals per playbook | Default 5,000; configurable from 1 to 10,000 |\n| Proposal review window | Default 30 days; configurable from 1 to 365 days |\n| Evidence records per proposal | 100 |\n| Total evidence payload per proposal | 256 KiB |\n| Individual evidence payload | 12 KiB |\n| Proposal creation source | 12 KiB |\n| Proposal search results | 1–50; default `10` |\n\nThe optional creation source is separate from attached evidence and does not increment `evidenceCount`. Unreviewed proposals leave the inbox at `inboxExpiresAt` and become unavailable after `purgeAt`. With the default policy, creation, new evidence, candidate replacement, and restoration set deadlines of 30 days for inbox review and 60 days for retention. Dismissing a proposal moves it to trash immediately and starts a 30-day retention window. An exact evidence retry does not refresh the deadlines.\n\nProposal retention does not affect an accepted entry's history. Store required review records outside the inbox."
    },
    {
      "id": "handle-request-errors",
      "title": "Handle request errors",
      "role": "content",
      "text": "HTTP errors include a status and machine-readable `type`. Use the type to choose a recovery action. For MCP, inspect `isError` before reading tool content. See [MCP troubleshooting](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/mcp#troubleshoot-the-connection).\n\n| Status | Meaning | Action |\n|:-------|:--------|:-------|\n| `400` | Invalid input, cursor, or unsupported request member. | Correct fields or restore the cursor's original request parameters. |\n| `401` | Authentication failed. | Check the endpoint and key, including expiry or revocation. |\n| `403` | The caller lacks access. | Check tenant, playbook, and action grants. `write` does not include `publish`. |\n| `404` | The requested resource is unavailable. | Check identifiers and retention. Rediscover a previously selected skill once. |\n| `409` | Content or review state conflicts with the request. | Inspect the error type and current state before changing the request. |\n| `412` | The proposal revision you supplied is no longer current (`/errors/revision-conflict`). | Read the proposal again, using `currentRevision` from the error, and review the current candidate before resubmitting. |\n| `413` | Content exceeds a payload limit. | Reduce the package, metadata, answer, or evidence payload. |\n| `423` | The playbook is suspended. | Ask the administrator to inspect its state. |\n| `424` | A required dependency failed. | Check playbook health and ask the administrator to inspect the dependency. |\n| `429` | Requests are throttled. | Use bounded backoff and honor `Retry-After` when supplied. |\n| `500` | An internal or content-integrity failure occurred. | Preserve safe diagnostic details and report persistent failures. Stored integrity failures require administrator investigation. |\n| `503` | The service or playbook is unavailable. | Check readiness and use bounded retries for safe operations. |\n\nFor example, inspect a failed entry read without retrying it automatically. Use the [client setup](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/quickstart#connect-to-the-playbook) and export the FAQ identifier you want to inspect:\n\n[code example]\n\n**Available in:** Python (Iris), cURL (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]"
    },
    {
      "id": "resolve-conflicts",
      "title": "Resolve conflicts",
      "role": "content",
      "text": "The `409` error type identifies the recovery step:\n\n| Error type | Action |\n|:-----------|:-------|\n| `/errors/entry-not-published` | Refresh retrieval or publish the intended version. |\n| `/errors/entry-key-conflict` | Use the existing entry or choose another key. |\n| `/errors/content-limit-exceeded` | Free retained capacity or confirm a higher supported deployment limit. |\n| `/errors/pinned-entry-unavailable` | Correct or remove the pin. |\n| `/errors/proposal-already-exists` | Inspect `existingId` or attach evidence to that proposal. |\n| `/errors/proposal-evidence-conflict` | Retry the original evidence payload or use a new evidence identifier for a new observation. |\n| `/errors/proposal-evidence-capacity` | Review the proposal with its retained evidence; additional evidence does not fit. |\n| `/errors/proposal-trashed` | Restore the proposal before modifying or accepting it. |\n| `/errors/proposal-open` | Dismiss the proposal before purging it. |\n| `/errors/proposal-promotion-locked` | Resume acceptance or use its recorded entry. Candidate edits and evidence changes are locked. |"
    },
    {
      "id": "retry-uncertain-operations",
      "title": "Retry uncertain operations",
      "role": "content",
      "text": "Use bounded retries for reads and transient failures. Proposal acceptance can resume its recorded target. For an exact evidence retry, keep the same identifier and payload.\n\nA timeout, including `408`, does not prove a create or append failed. Read state before retrying to avoid another entry or version. Check the Python SDK retry configuration when controlling write retries.\n\nBulk deletion is not atomic across the batch. The response lists removed entries in `deleted` and entries it couldn't delete in `errors`. Earlier deletions remain applied after a later failure. Retrying the same batch is safe because absent entries are ignored."
    },
    {
      "id": "remove-content-in-bulk",
      "title": "Remove content in bulk",
      "role": "content",
      "text": "Use a key with `write` permission for bulk deletion. Choose the entry type before sending a request:\n\n| Task | Python `.client` method | HTTP request |\n|:-----|:--------------|:-------------|\n| Delete selected FAQ entries and all their versions | `delete_faqs(entry_ids=...)` | `POST /iris/data/v1/agent-playbooks/playbooks/{playbookId}/faqs/bulk-delete` with an `entryIds` array |\n| Delete selected skills, versions, and files | `delete_skills(entry_ids=...)` | `POST /iris/data/v1/agent-playbooks/playbooks/{playbookId}/skills/bulk-delete` with an `entryIds` array |\n\nBulk deletion accepts 1–100 entry identifiers of the selected type. The data plane does not provide an operation to clear an entire playbook. An administrator can clear content through the control plane or the console's [Danger zone](https://redis.io/docs/latest/operate/iris/agent-playbook/manage-playbook#danger-zone).\n\nFor ordinary sample cleanup, use the single-entry deletion steps in [Manage FAQs](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-faqs#withdraw-or-delete-an-faq) or [Manage skills](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-skills#withdraw-or-delete-a-skill)."
    }
  ],
  "examples": [
    {
      "id": "handle-request-errors-ex0",
      "language": "bash",
      "code": "export PLAYBOOK_FAQ_ID='<faq-entry-id>'",
      "section_id": "handle-request-errors"
    },
    {
      "id": "handle-request-errors-ex1",
      "language": "python",
      "code": "import json\nimport os\nfrom redis_agent_playbook.errors import PlaybookError\n\ntry:\n    entry = playbook.client.get_faq(faq_id=os.environ[\"PLAYBOOK_FAQ_ID\"])\n    print(entry)\nexcept PlaybookError as error:\n    try:\n        problem = json.loads(error.body)\n    except ValueError:\n        problem = {}\n    print(\"Request failed:\", error.status_code, problem.get(\"type\", \"unknown\"))\n    raise",
      "section_id": "handle-request-errors"
    },
    {
      "id": "handle-request-errors-ex2",
      "language": "bash",
      "code": "STATUS=$(curl --silent --show-error -o response.json -w '%{http_code}' \\\n  \"$PLAYBOOK_API/faqs/$PLAYBOOK_FAQ_ID\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\")\nif [[ \"$STATUS\" == 2* ]]; then\n  jq . response.json\nelse\n  printf 'Request failed: HTTP %s\\n' \"$STATUS\" >&2\n  jq -r '.type // \"unknown\"' response.json >&2 2>/dev/null || printf 'unknown\\n' >&2\n  exit 1\nfi",
      "section_id": "handle-request-errors"
    }
  ]
}
