Error envelope
Read error.code for recovery logic. Show error.message to a developer.
JSON
{
"error": {
"code": "tool_result_invalid",
"message": "Tool result failed schema validation.",
"request_id": "request_123",
"details": [{"path": "content.title", "reason": "minLength"}]
}
}
Error codes
| Error code | Meaning |
|---|---|
invalid_request | HTTP 400. Fix the request body or parameter. |
invalid_cursor | HTTP 400. Restart replay without the bad cursor. |
authentication_required | HTTP 401. Send a valid bearer key. |
permission_denied | HTTP 403. Create a key with the required scope. |
resource_not_found | HTTP 404. Check the id and workspace. |
idempotency_conflict | HTTP 409. Reuse a key only with the same payload. |
event_already_resolved | HTTP 409. Do not execute the tool again. |
event_expired | HTTP 409. Start a new run. |
run_not_resumable | HTTP 409. Read the run status. Start a new run if it is terminal. |
SESSION_BUSY | HTTP 409. Wait, cancel, or resume the active run. |
RUN_NOT_CANCELLABLE | HTTP 409. Treat the run as already terminal. |
tool_input_invalid | HTTP 422. Fix the tool input schema or prompt. |
tool_result_invalid | HTTP 422. Return an object matching the tool output schema. |
RATE_LIMITED | HTTP 429. Wait for Retry-After before retrying. See Usage and limits. |
runtime_resume_unavailable | HTTP 503. Retry with the same idempotency key. |
SANDBOX_PROVISION_FAILED | HTTP 503. Retry later or remove an unnecessary sandbox requirement. |
SESSION_BUSY
HTTP 409
{
"error": {
"code": "SESSION_BUSY",
"message": "Session 'session_123' has an active run 'run_123' in status 'waiting_for_input'.",
"request_id": "request_123",
"active_run_id": "run_123",
"active_run_status": "waiting_for_input",
"recovery": [
"cancel the active run via POST /v1/sessions/session_123/runs/run_123/cancel",
"or resume it via POST /v1/sessions/session_123/runs/run_123/resume"
]
}
}
Read Sessions and runs for the recovery flow.
SANDBOX_PROVISION_FAILED
HTTP 503
{
"error": {
"code": "SANDBOX_PROVISION_FAILED",
"message": "Sandbox provider quota is exhausted. Please retry later.",
"request_id": "request_123"
}
}
RATE_LIMITED
Tenant requests share three independent 60-second limits: 30 sessions, 60 runs, and 120 events.
HTTP 429 includes a Retry-After header with the wait in seconds.
HTTP 429, Retry-After: 12
{
"error": {
"code": "RATE_LIMITED",
"message": "Tenant rate limit reached.",
"request_id": "request_123",
"details": {"limit": 30, "window_seconds": 60, "retry_after": 12}
}
}
details.limit is the configured request limit. details.window_seconds is the window length in seconds.
details.retry_after is the wait before retrying, matching the header.
See Usage and limits for affected operations. Request a higher limit through Support.
Recovery actions
| Symptom | Action |
|---|---|
| 409 busy | Use active_run_id. Resume or cancel that run. |
| 503 sandbox | Back off. Check quota. Disable sandboxing only when safe. |
| 401 | Send Authorization: Bearer PANTHEON_API_KEY. |
| 422 tool result | Validate the result against the registered output schema. |
| Stream drops | Reconnect with the last durable SSE id. Handle stream.resync. |
Pitfalls
- Error code casing differs: Use the exact code returned by the API. The contract contains lowercase and uppercase codes.
- A 422 leaves a run waiting: Correct the result and retry with the same idempotency key before the deadline.