|
| 1 | +# Errors |
| 2 | + |
| 3 | +> Spec reference: ARCP v1.1 §12 |
| 4 | +
|
| 5 | +All ARCP exceptions inherit from `ARCPError`. The 15 typed exceptions map 1:1 to spec §12 error codes and are importable from `arcp`. |
| 6 | + |
| 7 | +## Exception hierarchy |
| 8 | + |
| 9 | +``` |
| 10 | +ARCPError |
| 11 | +├── AuthenticationError (auth.failed) |
| 12 | +├── AuthorizationError (auth.unauthorized) |
| 13 | +├── AgentNotFoundError (agent.not_found) |
| 14 | +├── AgentVersionNotFoundError(agent.version_not_found) |
| 15 | +├── JobNotFoundError (job.not_found) |
| 16 | +├── JobCancelledError (job.cancelled) |
| 17 | +├── LeaseExceededError (lease.exceeded) |
| 18 | +├── LeaseExpiredError (lease.expired) |
| 19 | +├── LeaseDeniedError (lease.denied) |
| 20 | +├── DelegationError (delegation.invalid) |
| 21 | +├── ResumeError (resume.invalid) |
| 22 | +├── CapabilityError (capability.unsupported) |
| 23 | +├── RateLimitError (rate_limit.exceeded) |
| 24 | +├── InternalError (internal) |
| 25 | +└── ProtocolError (protocol) |
| 26 | +``` |
| 27 | + |
| 28 | +## Handling errors |
| 29 | + |
| 30 | +```python |
| 31 | +from arcp import ( |
| 32 | + ARCPError, |
| 33 | + AuthenticationError, |
| 34 | + LeaseExceededError, |
| 35 | + JobCancelledError, |
| 36 | + AgentNotFoundError, |
| 37 | +) |
| 38 | + |
| 39 | +try: |
| 40 | + handle = await client.submit(agent="my-agent", input={"x": 1}) |
| 41 | + result = await handle.done |
| 42 | +except AuthenticationError: |
| 43 | + # Token was rejected at session connect time |
| 44 | + print("Check your bearer token") |
| 45 | +except AgentNotFoundError: |
| 46 | + # Agent name not registered on the runtime |
| 47 | + print("Agent not found") |
| 48 | +except LeaseExceededError as e: |
| 49 | + # Job exceeded its cost or time budget |
| 50 | + print(f"Budget exceeded: {e.code}") |
| 51 | +except JobCancelledError: |
| 52 | + # Job was cancelled (by client or runtime) |
| 53 | + print("Job was cancelled") |
| 54 | +except ARCPError as e: |
| 55 | + # Catch-all for any other ARCP error |
| 56 | + print(f"ARCP error: {e.code} — {e.message}") |
| 57 | +``` |
| 58 | + |
| 59 | +## Error attributes |
| 60 | + |
| 61 | +Every `ARCPError` has: |
| 62 | + |
| 63 | +| Attribute | Type | Description | |
| 64 | +|---|---|---| |
| 65 | +| `code` | `str` | Spec error code, e.g. `"lease.exceeded"` | |
| 66 | +| `message` | `str` | Human-readable description | |
| 67 | +| `data` | `dict \| None` | Optional structured detail | |
| 68 | + |
| 69 | +## Raising errors from agents |
| 70 | + |
| 71 | +Agents can signal well-typed failures by raising `ARCPError` subclasses: |
| 72 | + |
| 73 | +```python |
| 74 | +from arcp import AuthorizationError |
| 75 | + |
| 76 | +async def admin_only(input, ctx): |
| 77 | + if ctx.principal != "admin@example.com": |
| 78 | + raise AuthorizationError("only admin can call this agent") |
| 79 | + return {"secret": 42} |
| 80 | +``` |
| 81 | + |
| 82 | +The runtime converts the exception into a `job.failed` event with the matching error code. |
| 83 | + |
| 84 | +## Catching errors inside agents |
| 85 | + |
| 86 | +Unhandled exceptions from agent functions are caught by the runtime and emitted as `job.failed` with `InternalError`. Catch expected exceptions explicitly: |
| 87 | + |
| 88 | +```python |
| 89 | +async def fragile_agent(input, ctx): |
| 90 | + try: |
| 91 | + result = await call_external_api(input) |
| 92 | + except httpx.TimeoutException as e: |
| 93 | + raise InternalError(f"external API timed out: {e}") from e |
| 94 | + return result |
| 95 | +``` |
| 96 | + |
| 97 | +## Related |
| 98 | + |
| 99 | +- [Troubleshooting](../troubleshooting.md) |
| 100 | +- [Leases guide](leases.md) — `LeaseExceededError`, `LeaseExpiredError` |
| 101 | +- [Auth guide](auth.md) — `AuthenticationError`, `AuthorizationError` |
0 commit comments