Service limits and errors
Find content and retrieval limits, proposal retention, error types, and retry guidance.
Check these limits when preparing content or handling request failures. Confirm deployment overrides with your administrator.
The API reference defines field formats and operation-specific schemas.
Content limits
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.
| Content | Default ceiling |
|---|---|
| Entries per playbook | 10,000 |
| Versions per entry | 100 |
| Retained content across an entry's versions | 256 MiB |
Files per skill version, including SKILL.md |
64 |
| ZIP archive entries, including directories | 256 |
| Compressed skill archive | 5 MiB |
| Expanded skill archive | 20 MiB |
| Individual skill file | 5 MiB |
Skill instructions file (SKILL.md) |
1 MiB |
| Version metadata | 64 KiB, nesting depth 16 |
Retained data includes version content and resources. Withdrawal does not free capacity; deletion removes the entry's history. You cannot delete an individual version.
These field and structure limits also apply:
| Field or structure | Limit |
|---|---|
| FAQ question | 2,048 characters |
| FAQ answer | 32,768 characters |
| Intents | Five per entry version; 2,048 characters each |
| Attributes | 32 names; up to 20 scalar items in each list value |
| Entry key or skill name | 64 characters |
| Skill description | 1,024 characters |
| Skill compatibility text | 500 characters |
Retrieval limits
| Request or setting | Limit or default |
|---|---|
| Search or discovery query | 1–4,096 characters |
| Type-specific search results | 1–50; omission uses the playbook's result default |
| Discovery results | 1–50, bounded by discovery.maxResults; service default 10, unified Python helper default 5 |
| Similarity thresholds | 0–1; default 0.7 for each entry type |
| Discovery preview ceiling | Disabled by default; minimum configured value 64 estimated tokens |
| Filter depth | Five |
| Equality predicates in a filter | 64 |
| Management list page | 1–200 results; default 50 |
| Entry lookup or bulk deletion | 1–100 entry references or identifiers |
Pins 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 for the behavior of each setting.
Follow 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.
List 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 for examples.
Proposal and evidence limits
| Limit or policy | Value |
|---|---|
| Open proposals per playbook | Default 5,000; configurable from 1 to 10,000 |
| Proposal review window | Default 30 days; configurable from 1 to 365 days |
| Evidence records per proposal | 100 |
| Total evidence payload per proposal | 256 KiB |
| Individual evidence payload | 12 KiB |
| Proposal creation source | 12 KiB |
| Proposal search results | 1–50; default 10 |
The 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.
Proposal retention does not affect an accepted entry's history. Store required review records outside the inbox.
Handle request errors
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.
| Status | Meaning | Action |
|---|---|---|
400 |
Invalid input, cursor, or unsupported request member. | Correct fields or restore the cursor's original request parameters. |
401 |
Authentication failed. | Check the endpoint and key, including expiry or revocation. |
403 |
The caller lacks access. | Check tenant, playbook, and action grants. write does not include publish. |
404 |
The requested resource is unavailable. | Check identifiers and retention. Rediscover a previously selected skill once. |
409 |
Content or review state conflicts with the request. | Inspect the error type and current state before changing the request. |
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. |
413 |
Content exceeds a payload limit. | Reduce the package, metadata, answer, or evidence payload. |
423 |
The playbook is suspended. | Ask the administrator to inspect its state. |
424 |
A required dependency failed. | Check playbook health and ask the administrator to inspect the dependency. |
429 |
Requests are throttled. | Use bounded backoff and honor Retry-After when supplied. |
500 |
An internal or content-integrity failure occurred. | Preserve safe diagnostic details and report persistent failures. Stored integrity failures require administrator investigation. |
503 |
The service or playbook is unavailable. | Check readiness and use bounded retries for safe operations. |
For example, inspect a failed entry read without retrying it automatically. Use the client setup and export the FAQ identifier you want to inspect:
export PLAYBOOK_FAQ_ID='<faq-entry-id>'
import json
import os
from redis_agent_playbook.errors import PlaybookError
try:
entry = playbook.client.get_faq(faq_id=os.environ["PLAYBOOK_FAQ_ID"])
print(entry)
except PlaybookError as error:
try:
problem = json.loads(error.body)
except ValueError:
problem = {}
print("Request failed:", error.status_code, problem.get("type", "unknown"))
raise
from redis_iris.agent_playbooks import AgentPlaybooks
playbook = AgentPlaybooks.from_env()
print(playbook.client.get_playbook_health())
import json
import os
from redis_agent_playbook.errors import PlaybookError
try:
entry = playbook.client.get_faq(faq_id=os.environ["PLAYBOOK_FAQ_ID"])
print(entry)
except PlaybookError as error:
try:
problem = json.loads(error.body)
except ValueError:
problem = {}
print("Request failed:", error.status_code, problem.get("type", "unknown"))
raise
STATUS=$(curl --silent --show-error -o response.json -w '%{http_code}' \
"$PLAYBOOK_API/faqs/$PLAYBOOK_FAQ_ID" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY")
if [[ "$STATUS" == 2* ]]; then
jq . response.json
else
printf 'Request failed: HTTP %s\n' "$STATUS" >&2
jq -r '.type // "unknown"' response.json >&2 2>/dev/null || printf 'unknown\n' >&2
exit 1
fi
set -euo pipefail
set -euo pipefail
PLAYBOOK_API="${IRIS_AGENT_PLAYBOOKS_URL%/}/iris/data/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID"
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/health" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" | jq .
STATUS=$(curl --silent --show-error -o response.json -w '%{http_code}' \
"$PLAYBOOK_API/faqs/$PLAYBOOK_FAQ_ID" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY")
if [[ "$STATUS" == 2* ]]; then
jq . response.json
else
printf 'Request failed: HTTP %s\n' "$STATUS" >&2
jq -r '.type // "unknown"' response.json >&2 2>/dev/null || printf 'unknown\n' >&2
exit 1
fi
Resolve conflicts
The 409 error type identifies the recovery step:
| Error type | Action |
|---|---|
/errors/entry-not-published |
Refresh retrieval or publish the intended version. |
/errors/entry-key-conflict |
Use the existing entry or choose another key. |
/errors/content-limit-exceeded |
Free retained capacity or confirm a higher supported deployment limit. |
/errors/pinned-entry-unavailable |
Correct or remove the pin. |
/errors/proposal-already-exists |
Inspect existingId or attach evidence to that proposal. |
/errors/proposal-evidence-conflict |
Retry the original evidence payload or use a new evidence identifier for a new observation. |
/errors/proposal-evidence-capacity |
Review the proposal with its retained evidence; additional evidence does not fit. |
/errors/proposal-trashed |
Restore the proposal before modifying or accepting it. |
/errors/proposal-open |
Dismiss the proposal before purging it. |
/errors/proposal-promotion-locked |
Resume acceptance or use its recorded entry. Candidate edits and evidence changes are locked. |
Retry uncertain operations
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.
A 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.
Bulk 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.
Remove content in bulk
Use a key with write permission for bulk deletion. Choose the entry type before sending a request:
| Task | Python .client method |
HTTP request |
|---|---|---|
| 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 |
| 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 |
Bulk 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.
For ordinary sample cleanup, use the single-entry deletion steps in Manage FAQs or Manage skills.