Skip to main content
Every non-2xx response from the Cactal API — and every failed MCP tool call — carries the same body shape:
  • kind — a stable, machine-readable category. Branch on this, never on message.
  • message — a human-readable explanation. Wording may change.
  • suggestion: present when the failure has a known fix: what to do next, often naming the exact operation to call (for example a stale edit lease points at websiteSourceCode.lease.acquire).
  • validValues: present when the failing field accepts a closed set of values: the accepted values.
  • Some errors add further detail fields alongside these (for example retryAfterSeconds on rate limits, or framework diagnostics on failed builds).

Error kinds

validation

The request was well-formed HTTP but failed schema validation. The message names the first invalid field, and closed-set fields include their accepted values in validValues.
Suggested action: fix the named field and resend. Validation failures are never retryable as-is.
Framework build failures also surface as validation errors — on head/check, head/publish, and deployment/ensure — with diagnostic details describing each source error. Fix the source files they point at, then retry.

unauthorized

No usable credential. The key is missing, malformed, expired, or revoked — or you sent a browser session cookie to api.cactal.ai.
Suggested action: send Authorization: Bearer <key> with an active key. If the key was rotated, update the stored secret. Repeated auth failures from one IP are rate limited — see Rate limits.

forbidden

The key authenticated, but its role does not grant the capability this endpoint requires (shown as x-cactal-required-capability on each endpoint page).
Suggested action: use a key whose scope and role cover the operation, or rescope the key by sending access to PATCH /v1/apiKeys/{apiKeyId}. Do not retry with the same key.

not_found

The resource does not exist — or it exists but is outside your key’s access scope. Cactal deliberately returns 404 instead of 403 for cross-tenant requests so resource existence never leaks between organizations.
Suggested action: check the id and confirm the key’s scope includes the resource’s organization or website. An agent seeing 404 on an id it just received should stop and re-check its scope rather than retry.

conflict

The request contradicts current state: a duplicate slug or field key, a resource cap reached, or a delete blocked by incoming references. The message states the specific conflict.
Suggested action: resolve the stated conflict (pick a new slug, remove references, raise capacity) and resend.

rate_limited

You exceeded a rate-limit bucket. The response includes a Retry-After header (seconds) and mirrors it in the body:
Suggested action: wait retryAfterSeconds, then retry. Sustained 429s mean you should queue and pace requests — see Rate limits for the exact buckets.

internal

Something failed on Cactal’s side. The request may or may not have taken effect.
Suggested action: retry with exponential backoff. For non-idempotent operations (marked x-cactal-idempotent: false), read the resource first to confirm whether the change landed before retrying.

Errors over MCP

MCP tool calls run the identical pipeline. Failures come back as tool results with isError: true and the same { kind, message, ... } payload as JSON content, so agents can branch on kind exactly like HTTP clients do.