Files
cleveragents-core/docs/reference/error_handling.md
T
2026-02-25 10:05:57 +00:00

6.5 KiB

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.

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
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:

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

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:

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

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