Errors, Rate Limits, and Pagination
Chab uses stable error codes and machine-readable response metadata so scripts and coding agents can recover safely.
Error Envelope
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Retry after the provided delay.",
"retryable": true
},
"request_id": "req_123"
}
error.details is present only when the error includes structured field-level
information. Validation failures include it:
{
"error": {
"code": "validation_failed",
"message": "One or more fields failed validation.",
"retryable": false,
"details": {
"data": [
"The data field must be an array."
]
}
},
"request_id": "req_123"
}
Billing and free-use errors also include error.user_action, a short sentence
an agent can pass on to the person, so CLI, MCP and API clients can show the
next step without fetching the catalog first. Errors about credits or a missing
account (signup_required, free_credits_exhausted, insufficient_credits)
add a link:
- For a guest trial:
error.signup_url, pluserror.next_steptelling the agent to ask the person for their email address and callchab_sign_up(hosted MCP) orPOST /v1/signup(guest key). The person confirms by email and the trial moves into their new account. - For an account:
error.upgrade_url, where the signed-in person can see plans and buy credit packs.
Hosted MCP tool errors carry the same fields.
Error documentation should explain:
- what happened
- whether the request can be retried
- whether credits can be charged
- what the user should do next
Authentication and scope error codes are listed in
Authentication and API Keys, including guest trial API
credential lifecycle errors such as guest_credential_expired,
guest_credential_revoked, and guest_credential_limit_exceeded.
Foundation Error Codes
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
validation_failed |
422 | No | No | Fix the fields listed in error.details. |
malformed_request_body |
400 | No | No | Send valid JSON when using a JSON Content-Type. |
idempotency_key_required |
400 | No | No | Add an Idempotency-Key header. |
idempotency_key_invalid |
400 | No | No | Use 8 to 255 letters, digits, ., _, -, or :. |
idempotency_key_conflict |
409 | No | No | Use a new key, or retry with the exact original body. |
idempotency_request_in_progress |
409 | Yes | No | Wait for Retry-After, then retry the same key and body. |
operation_result_not_ready |
409 | Yes | No | Wait for Retry-After, then fetch the result again or poll the status URL. |
rate_limited |
429 | Yes | No | Slow down or wait for Retry-After. |
not_found |
404 | No | No | Check the path and API version. |
method_not_allowed |
405 | No | No | Use a documented method for the endpoint. |
server_error |
500 | Yes | No | Retry later; reuse the same idempotency key for idempotent requests. |
The full machine-readable catalog is available from GET /v1/errors.
For a mutating /v1 request, X-Chab-Idempotency-Outcome: released means
the processing claim was removed and no operation was accepted by that
attempt; settled means the response was durably saved for that key, including
when that saved response is replayed. A
429 without this header may have been rejected before idempotency was
checked, so after an uncertain network failure retry the same key and body
to reconcile it. Do not switch to a new key merely because a retry returned
an unmarked 429 or idempotency_request_in_progress.
An unmarked server error or in-progress response can also follow a committed
operation, file, billing hold, or an uncertain mail-provider submission. Keep
the same key and body while reconciling; do not infer that a new key is safe.
Operation artifact, artifact download, single-cancel, and bulk-cancel endpoints
reuse the standard auth, not_found, rate_limited, server_error,
validation_failed, and idempotency error codes where applicable.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
artifact_creation_failed |
500 | Yes | No | Retry later by starting a new operation with a new idempotency key. |
Start Safety and Policy Errors
These checks happen before rate consumption, credit reservation, operation creation, callback-secret storage, or provider work. They are not chargeable. For an idempotent start, Chab releases the processing claim so the same key and body can be retried after remediation.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
operation_family_degraded |
503 | Yes | No | The tool family is paused for a short time. Wait for Retry-After, check service health, then retry the same request. |
operation_family_disabled |
503 | No | No | The tool is switched off. Do not retry in a loop; check service health and retry only after it is switched back on. |
security_restriction_active |
403 | No | No | Review the security notice or contact authenticated support. |
secret_content_detected |
422 | No | No | Remove credentials or secret-like content from the request. |
secret_scan_unavailable |
503 | Yes | No | Retry the unchanged request later. |
policy_acceptance_required |
403 | No | No | Ask an authorized natural user to accept the policy versions listed in the response. |
See Service Health for what the two operation family codes mean and how a paused family reopens.
Connected Data Errors
Chab authorizes the project before looking up an exact connection, so missing,
cross-team, cross-project, deleted, and ungranted identifiers all return
not_found. The more specific errors below appear only after project ownership
has been established. connected_data is the emitted_by catalog value for
these errors.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
connection_action_required |
409 | No | No | Repair, reconnect, reauthorize, or replace the connection, then reuse the idempotency key when applicable. |
connection_temporarily_unavailable |
503 | Yes | No | Wait for Retry-After (always 5–300 seconds), then retry the same request and key. |
connection_capability_unavailable |
422 | No | No | Choose or update a connection that exposes the exact required capability. |
connection_access_removed |
409 | No | Yes | Restore access before starting new work. Already-incurred accepted work may still settle. |
The first three errors happen before request acceptance and release a mutable
idempotency claim. No operation, new hold, callback secret, or provider effect
is created. Although action-required and capability-unavailable are not
retryable without remediation, the released key may be reused after the
connection changes. Protected operation reads continue to use not_found
instead of revealing a retained inaccessible operation.
Billing and Credit Errors
Billing and credit errors are not retryable until the billing state, plan,
operation family, or credit balance changes. They are not chargeable. When
Chab returns insufficient_credits, no operation work has started and no
credits have been held or charged.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
paid_plan_required |
403 | No | No | Subscribe or upgrade before using operations that require a paid API plan. |
subscription_unhealthy |
402 | No | No | Fix the billing or payment state, or contact support. |
api_access_not_included |
403 | No | No | Upgrade to a plan that includes paid API access, then retry. |
operation_family_not_included |
403 | No | No | Upgrade to a plan that includes the requested operation family, then retry. |
spend_threshold_exceeded |
402 | No | No | Lower the request budget, raise your operation spend threshold, or move to a larger plan. |
token_spending_disabled |
403 | No | No | Ask a team owner to enable spending for this API key. |
token_budget_exceeded |
402 | No | No | Reduce the request cost or ask a team owner for a new allowance. |
insufficient_credits |
402 | No | No | Purchase credits where available, add billing capacity, or reduce the requested operation size. |
max_budget_exceeded |
402 | No | No | Raise max_credit_budget, reduce requested output size, or choose a lower-cost model alias. |
Free-Mode Operation Errors
Some operations may be available through a free promotional allowance. Free operation starts never fall back to paid credits automatically. If the request cannot run on free credits, no operation work starts, no provider work is dispatched, and no paid credits are held.
free_credits_exhausted means the beneficiary has no unexpired free-credit lot
capacity for the requested estimate or estimate increase. For verified free
accounts, this usually means the one-off signup bonus has already been spent or
is reserved by accepted work. Free promotional credits do not refresh monthly.
Expired lots and already-held free credits are not counted as available for new
free-funded work. Guest trial credits are one-off; a new credential does not
refresh them. An active guest trial can move into a free account: at sign-up in
the same browser, or through the agent with chab_sign_up or POST /v1/signup.
Expired trials cannot be moved. For signed-in accounts whose free balance is
used up, error.upgrade_url shows plans and credit packs, which are coming
soon.
promotional_budget_exhausted means free credits are paused for a while,
usually because Chab's daily free-use limit has been reached. Wait for
Retry-After when provided, then retry. Work paid with your own credits is not
affected. Free starts that include one-off
callback fields return validation_failed before callback-secret storage,
operation creation, credit holds, or provider dispatch; omit those fields and
poll instead.
When a free request returns challenge_required, error.details.challenge
identifies the verification provider, action, response field, and challenge
expiry. Browser-trial clients render the challenge, submit the returned token
using the named response field, and retry the same request. Failed or expired
challenge attempts do not create an operation, reserve credits, or dispatch
provider work. If the challenge provider is temporarily unavailable, Chab
returns promotional_budget_exhausted with Retry-After instead of counting a
failed challenge attempt.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
free_credits_exhausted |
402 | No | No | Trial and bonus credits are one-off. Guests: create a free account (signup_url, or the agent signs the person up). Accounts: choose a plan or buy credit packs at upgrade_url. |
signup_required |
401 | No | No | This guest trial cannot start new work. Create a free account (signup_url, or the agent signs the person up) or sign in. |
email_verification_required |
403 | No | No | Verify the email address on your account, then retry. |
upgrade_required |
403 | No | No | Upgrade before retrying the operation. |
free_usage_paused |
429 | Yes | No | Wait for Retry-After when provided, then retry. |
challenge_required |
403 | Yes | No | Complete the required verification challenge, then retry. |
market_not_eligible |
403 | No | No | Use a paid plan or try again from an eligible market. |
operation_not_available_on_free |
403 | No | No | This operation is not available to the current free credential. Check its current availability and connection requirements. |
guest_credential_limit_exceeded |
429 | No | After Retry-After for rolling issuance limits. |
Revoke an older credential only for an active-count limit; otherwise wait for the issuance window to recover. |
promotional_budget_exhausted |
503 | Yes | No | Free use is paused for a while. Wait for Retry-After when provided, then retry. Paid credits are not affected. |
Quota Errors
Billable operation starts can be limited by plan, API key, team, operation family, and usage window. Daily windows use a UTC calendar day. Monthly windows reset with the team's monthly credit cycle.
Quota errors are not chargeable and do not create an operation.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
quota_exceeded |
429 | No | No | Wait for the day or month quota window to reset, reduce starts for that family, or move to a larger plan. |
concurrency_limit_exceeded |
429 | Yes | No | Retry when an active operation completes, reduce parallel starts, or move to a larger plan. |
Provider Throttling
provider_temporarily_rate_limited means Chab accepted the request path but a
provider is temporarily unable to accept more work. Chab may keep an
operation in running while retrying internally. If retries are exhausted, the
terminal operation keeps this provider-neutral code. Retry guidance comes from
the error catalog and any Retry-After or polling hints; failed terminal
operations do not use warnings for retry advice. The response does not expose
internal provider names.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
provider_temporarily_rate_limited |
503 | Yes | No | For active operations, keep polling with next_check_at or Retry-After. If terminal, create a new operation later or retry the original idempotent request when safe. |
Target URL Errors
URL-based operations can publish target URL errors when a target cannot be used safely or when target fetch/render work times out.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
target_fetch_blocked |
422 | No | No | Check that the URL is public, supported, reachable, and does not redirect to a private or unsafe destination. |
target_timeout |
504 | Yes | Yes, after work starts | Retry later, reduce target complexity, or use operation-specific rendering and wait options. |
Source Input Errors
File and artifact based operations can publish source-state errors before work
starts. Missing, cross-team, or unauthorized sources return not_found without
disclosing which condition applied.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
file_expired |
410 | No | No | Upload or select a fresh file source. |
artifact_expired |
410 | No | No | Use a non-expired artifact. |
artifact_deletion_in_progress |
409 | Yes | No | Respect Retry-After, then retry the artifact request. |
artifact_deletion_failed |
503 | Yes | No | Contact support with the public artifact reference. |
source_scan_pending |
409 | Yes | No | Wait for scanning to finish, then retry. |
source_scan_failed |
422 | No | No | Upload or select a clean supported source. |
source_quarantined |
422 | No | No | Choose a different source or contact support. |
Provider Errors
Provider errors mean the service Chab uses to complete an operation is not available, returned an unusable response, or could not finish the request. Chab keeps these errors provider-neutral and does not expose provider task IDs, raw responses, or internal provider names.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
provider_unavailable |
503 | Yes | No | For an active operation, keep polling. For a terminal response, retry later with the same idempotency key when the endpoint is idempotent. |
provider_error |
502 | No | No | Check the request input and operation warnings before retrying. |
provider_response_invalid |
502 | Yes | No | Retry later with the same idempotency key when the endpoint is idempotent. |
When a new start returns provider_unavailable, no provider is ready for that
tool right now. Nothing is billed, the idempotency key is released, and the
response includes Retry-After. Other tools keep working.
Scrape operations also publish extraction errors. Screenshot operations publish capture errors. See Scrape Endpoints and Screenshot Endpoints for operation-specific charge and retry rules.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
selector_not_found |
422 | No | Yes | Check the selector or capture the viewport/full page instead. |
capture_timeout |
504 | Yes | Yes | Retry later, reduce capture complexity, or capture a smaller viewport. |
capture_failed |
502 | No | Yes | Check the request options and target behavior before retrying. |
Convert operations publish conversion-specific errors. See Convert Endpoints for supported source/output pairs and endpoint examples.
Translation operations publish translation-specific validation errors. See Translation Endpoints for supported formats, source limits, repair behavior, and charge rules.
LLM operations publish model-alias, context, structured-output, tool-call, embedding-size, and oversized-response errors. See LLM Endpoints for charge and retry rules.
Research operations publish budget, timeout, and citation-extraction errors. See Research Endpoints for mode limits, source-budget semantics, partial-result behavior, and charge rules.
| Code | HTTP | Retry | Chargeable | What to do |
|---|---|---|---|---|
unsupported_file_type |
422 | No | No | Use a supported source category. |
unsupported_conversion_pair |
422 | No | No | Pick an output format supported by the source category. |
unsupported_file_content |
422 | No | No | Use a file with extractable text. |
conversion_timeout |
504 | Yes | Yes, after work starts | Retry later or reduce source complexity. |
conversion_failed |
502 | No | Yes, after work starts | Check the source and output format before retrying. |
unsupported_format |
422 | No | No | Use a supported translation format or artifact. |
source_too_large |
422 | No | No | Reduce translation source content to 100,000 characters or less. |
structure_validation_failed |
422 | No | Yes, after work starts | Split or simplify the source and retry. |
placeholder_integrity_failed |
422 | No | Yes, after work starts | Check placeholders and retry with a simpler source if needed. |
repair_exhausted |
422 | No | Yes, after work starts | Split the source, simplify glossary or placeholder requirements, then retry. |
research_budget_exhausted |
402 | No | No before dispatch; possible after work starts | Start a new research operation with a larger max_credit_budget, smaller source_budget, or cheaper mode. |
research_timeout |
504 | No | Yes, after work starts | Start a new operation later, narrow the question, reduce source_budget, or choose a faster mode. |
citation_extraction_failed |
502 | No | Yes, after work starts | Start a new operation with a clearer research question or narrower source guidance. |
Resource Errors
These errors describe resource behavior shared by more than one API family. They are nonretryable and nonchargeable unless the endpoint documentation says otherwise.
| Code | HTTP | What to do |
|---|---|---|
inline_content_too_large |
413 | Request a smaller page or reduce content below the endpoint's documented inline limit. |
range_not_supported |
416 | Remove the Range header and request the complete resource. |
resource_revision_conflict |
409 | Read the current resource and retry with its latest revision. |
resource_state_conflict |
409 | Read the resource and resolve the current state that blocks the requested action. |
Drive API Errors
Drive API routes are non-billable. Chab-served download bytes can still incur egress credits as documented by the endpoint.
| Code | HTTP | Retry | What to do |
|---|---|---|---|
drive_item_action_unavailable |
422 | No | Re-read the item and use only an action currently advertised for it. |
drive_export_format_unavailable |
422 | No | Re-read the item and choose one of its current export formats. |
drive_item_too_large |
413 | No | Download a file no larger than the endpoint's 100 MiB delivery limit. |
drive_export_too_large |
413 | No | Export a document whose produced artifact fits the 100 MiB limit. |
Mail API Errors
Mail API routes are synchronous and not billable, so every error below is nonchargeable. They also use the standard validation, authentication, plan, scope, connected-data, provider, rate-limit, and idempotency errors documented elsewhere on this page.
| Code | HTTP | Retry | What to do |
|---|---|---|---|
attachment_too_large |
413 | No | Download or stage a smaller attachment, or remove another staged attachment. |
source_too_large |
422 | No | Use a reusable artifact no larger than 26,214,400 bytes. |
not_found deliberately covers inaccessible projects, connections, messages,
drafts, folders, attachments, and artifacts without confirming whether a
resource exists outside the current API key's authorization.
Source Size Errors
source_too_large means a reusable input exceeds the endpoint's per-source
limit. It is a nonretryable, nonchargeable 422; use a smaller source or split
the content. Mail draft attachments allow at most 26,214,400 bytes per source.
Other endpoint families can document a different, smaller limit.
Structured Warnings and Availability
Successful operations can include warnings in status and result responses:
{
"code": "result_truncated",
"message": "Results were capped at 10 rows.",
"field": "results",
"severity": "info"
}
Warning codes are partial_results, field_unavailable,
unsupported_field, stale_data, low_confidence,
duplicate_candidate, result_truncated, glossary_preferred_missed, and
provider_degraded.
Severity is info or warning; field is nullable.
Availability metadata uses these values: available, missing,
unsupported, unavailable, withheld, stale, low_confidence, and
unknown.
Idempotency
Mutating foundation requests require an Idempotency-Key header. The key must
be 8 to 255 characters and may contain letters, digits, periods, underscores,
hyphens, and colons.
Within the 24 hour idempotency window:
- Idempotency keys are scoped to the authenticated team API key, HTTP method, endpoint operation, and any resource identifiers in the path. Reusing the same key on a different endpoint or path target starts a separate idempotency record.
- On the same endpoint and path target, the same key and byte-identical request body replays the stored response.
- On the same endpoint and path target, the same key with a different request
body returns
idempotency_key_conflict. - A second request while the first one is still processing returns
idempotency_request_in_progressandRetry-After. - Validation failures are replayable.
- Unexpected server errors are not cached as final responses, so a later retry can recover after the processing lease expires. If durable work already exists, the retry reattaches that work before starting anything new or remains in progress; it never creates a second charge under the same key.
- A currently valid credential may reconcile a previously accepted operation with the same key after a plan or funding change, even when a new operation would now be denied. Revoked or claimed guest credentials do not regain access for replay; after claiming a guest trial, use the claimed account's operation history instead.
- Claims tied to retained operations, files, pending purchases, or uncertain mail sends may be kept beyond the usual 24-hour replay window so a retry cannot silently replace their identity. Continue using the original key and body while the work is being reconciled.
- Mutable connection-state denials release the processing row. Reuse the same key and byte-identical body only after the documented repair or retry delay.
Rate Limit Headers
Chab returns RFC 9333 rate-limit headers where possible:
RateLimit-Limit: 100
RateLimit-Remaining: 42
RateLimit-Reset: 60
For 429 responses, Chab also returns:
Retry-After: 60
The foundation limiter applies to /v1 route families, including billable
starts, and may
also include legacy X-RateLimit-* headers for compatibility. Billable
operation starts use plan- and family-aware limits keyed by team, API key,
operation family, and route profile. The RFC 9333 RateLimit-* headers are the
contract.
For 429 and retryable 503 usage responses, use Retry-After as the minimum
delay before retrying. For quota and spend errors, also review
Credits and Billing before retrying.
Operation status and result endpoints also use Retry-After for active
operations and not-ready results. See Operations.
Deprecation and Sunset Headers
When Chab deprecates a public API field or endpoint, responses can include:
Deprecation: @1794355200
Sunset: Wed, 11 Nov 2026 00:00:00 GMT
Link: <https://www.chab.ai/docs/deprecations/example>; rel="deprecation"
If both Deprecation and Sunset apply, the Link header can include both
rel="deprecation" and rel="sunset" references.
Inline Result Size
Inline JSON data is limited to 1 MB after serialization unless an endpoint
documents a smaller limit. Larger results are returned through artifacts or
files instead of one huge response body.
Pagination
List endpoints use cursor pagination:
{
"data": [],
"meta": {
"next_cursor": "cursor_abc",
"prev_cursor": null,
"has_more": true,
"limit": 50,
"request_id": "req_123"
}
}
Default page size is 50. Maximum page size is 100 unless an endpoint documents a smaller cap.
GET /v1/operations uses this same pagination shape.