Files
temp/docs/reference/error_handling.md
T
eugen.thaci f66fb5a19a docs(spec): align ASCII UI tables in specification and related pages
Align Unicode box-drawing blocks and related tables in specification.md,
ADR-044/045/046, and reference pages for consistent MkDocs rendering.

ISSUES CLOSED: #1171
2026-04-03 04:55:21 +00:00

197 lines
6.5 KiB
Markdown

# Error Handling
## Overview
The `cleveragents.core.error_handling` module provides centralized
error classification, secret redaction, and exception wrapping for
consistent CLI output and safe logging.
Secret redaction **delegates** to `cleveragents.shared.redaction` so
that all redaction paths (structlog processors, CLI output, error
details) share the same patterns and configuration. On import, the
module registers additional patterns (JWT, GitHub PAT, GitLab PAT)
with the shared redaction registry.
## CLI Integration
The top-level CLI error handlers in `cli/main.py` use `classify_error`
and `wrap_unexpected` to ensure every exception surfaced to the user
is classified with an HTTP-like error code and has secrets redacted
from both the message and any attached details.
```python
except CleverAgentsError as e:
from cleveragents.core.error_handling import classify_error
info = classify_error(e)
print(f"Error [{info.code.value}] {info.code.name}: {info.message}")
except Exception as e:
from cleveragents.core.error_handling import classify_error, wrap_unexpected
safe = wrap_unexpected(e)
info = classify_error(safe)
print(f"Error [{info.code.value}] {info.code.name}: {info.message}")
```
## Error Codes
All errors are mapped to HTTP-like numeric codes:
### Client Errors (400-range)
| Code | Name | Mapped From |
|------|---------------------|-------------------------------|
| 400 | BAD_REQUEST | BusinessRuleViolation, PlanError, DomainError |
| 401 | UNAUTHORIZED | AuthenticationError |
| 403 | FORBIDDEN | AuthorizationError |
| 404 | NOT_FOUND | ResourceNotFoundError |
| 409 | CONFLICT | ResourceConflictError |
| 422 | VALIDATION_FAILED | ValidationError |
| 429 | RATE_LIMITED | RateLimitError |
### Server Errors (500-range)
| Code | Name | Mapped From |
|------|---------------------|-------------------------------|
| 500 | INTERNAL | InfrastructureError, CleverAgentsError (catch-all) |
| 503 | SERVICE_UNAVAILABLE | ExternalServiceError |
| 520 | PROVIDER_ERROR | ProviderError |
| 521 | EXECUTION_ERROR | ExecutionError |
| 522 | DATABASE_ERROR | DatabaseError |
| 523 | FILESYSTEM_ERROR | FileSystemError |
| 524 | NETWORK_ERROR | NetworkError |
| 525 | CONFIGURATION_ERROR | ConfigurationError |
| 526 | TOKEN_LIMIT | TokenLimitExceededError |
| 527 | MODEL_UNAVAILABLE | ModelNotAvailableError |
| 528 | STREAM_ERROR | StreamRoutingError |
## Error Categories
Each `ErrorInfo` includes a `category` field derived from the error code:
| Value | Name | Code Range | Description |
|-------|--------|------------|--------------------------|
| 4 | CLIENT | 400-499 | Client / input errors |
| 5 | SERVER | 500-599 | Server / infrastructure |
```python
from cleveragents.core.error_handling import classify_error, ErrorCategory
info = classify_error(exc)
if info.category == ErrorCategory.CLIENT:
print("User-correctable error")
```
## Secret Redaction
Redaction is handled by `cleveragents.shared.redaction` (the single
source of truth for all secret masking). The `redact_error_details`
function in this module is a thin wrapper around `redact_dict` that
forces `show_secrets=False` so error details are **always** masked.
### Redacted Keys (via `shared.redaction`)
Key names are matched by **substring** against the shared sensitive
key list: `api_key`, `apikey`, `password`, `passwd`, `secret`,
`token`, `credential`, `private_key`, `access_key`, `auth`.
False positives like `token_count` and `max_tokens` are excluded.
### Pattern-Based Redaction
String values are scanned for secret patterns from the shared
registry plus the additional patterns registered by this module:
- OpenAI API keys (`sk-...`, `sk-proj-...`)
- Anthropic keys (`sk-ant-...`)
- JWT tokens (`eyJ...`)
- GitHub PATs (`ghp_...`, `ghs_...`)
- GitLab PATs (`glpat-...`)
- Bearer tokens
- Token IDs (`tok_...`)
### Single-Value Redaction
The `redact_value` function (re-exported from `cleveragents.shared.redaction`)
scans a single string for secret patterns and replaces matches:
```python
from cleveragents.core.error_handling import redact_value
safe = redact_value("token is sk-abcdefghijklmnopqrstuvwxyz")
# => "token is ***REDACTED***"
```
This is the same function used internally by `classify_error` to redact
exception messages before they reach CLI output.
### Dict Redaction
```python
from cleveragents.core.error_handling import redact_error_details
safe = redact_error_details({
"api_key": "sk-real-secret",
"plan_id": "01PLAN001",
})
# => {"api_key": "***REDACTED***", "plan_id": "01PLAN001"}
```
## Wrapping Unexpected Exceptions
Use `wrap_unexpected` to convert non-`CleverAgentsError` exceptions
into safe, user-facing errors:
```python
from cleveragents.core.error_handling import wrap_unexpected
try:
risky_operation()
except Exception as exc:
safe = wrap_unexpected(exc, context={"plan_id": plan_id})
raise safe from exc
```
If the exception is already a `CleverAgentsError`, it is returned
with optional context merged into a **copy** of its details (the
original details dict is not mutated).
## CLI Formatting
```python
from cleveragents.core.error_handling import classify_error, format_error_for_cli
info = classify_error(exc)
print(format_error_for_cli(info))
# Error [422] VALIDATION_FAILED: name is required
```
Note: `classify_error` redacts secrets from the exception **message**
as well as from its details, so the output is always safe to display.
## Exception Hierarchy
```
CleverAgentsError
├── DomainError
│ ├── ValidationError
│ ├── BusinessRuleViolation
│ ├── ResourceNotFoundError
│ ├── ResourceConflictError
│ └── PlanError
├── InfrastructureError
│ ├── DatabaseError
│ ├── NetworkError
│ └── ExternalServiceError
├── ProviderError
│ ├── RateLimitError
│ ├── TokenLimitExceededError
│ └── ModelNotAvailableError
├── AuthenticationError
├── AuthorizationError
├── ConfigurationError
│ └── MissingConfigurationError
├── FileSystemError
├── ExecutionError
└── StreamRoutingError
```