0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
252 lines
5.4 KiB
Markdown
252 lines
5.4 KiB
Markdown
# Error Handling
|
|
|
|
Headroom provides explicit exceptions for debugging, with a safety guarantee that compression failures never break your LLM calls.
|
|
|
|
## Exception Hierarchy
|
|
|
|
```python
|
|
from headroom import (
|
|
HeadroomError, # Base class - catch all Headroom errors
|
|
ConfigurationError, # Invalid configuration
|
|
ProviderError, # Provider issues (unknown model, etc.)
|
|
StorageError, # Database/storage failures
|
|
CompressionError, # Compression failures (rare)
|
|
ValidationError, # Setup validation failures
|
|
)
|
|
```
|
|
|
|
## Usage
|
|
|
|
```python
|
|
from headroom import (
|
|
HeadroomClient,
|
|
HeadroomError,
|
|
ConfigurationError,
|
|
StorageError,
|
|
)
|
|
|
|
try:
|
|
client = HeadroomClient(...)
|
|
response = client.chat.completions.create(...)
|
|
|
|
except ConfigurationError as e:
|
|
print(f"Config issue: {e}")
|
|
print(f"Details: {e.details}") # Additional context
|
|
|
|
except StorageError as e:
|
|
print(f"Storage issue: {e}")
|
|
# Headroom continues to work, just without metrics persistence
|
|
|
|
except HeadroomError as e:
|
|
print(f"Headroom error: {e}")
|
|
```
|
|
|
|
## Exception Types
|
|
|
|
### ConfigurationError
|
|
|
|
Raised when configuration is invalid.
|
|
|
|
```python
|
|
# Examples:
|
|
# - Invalid mode value
|
|
# - Missing required provider
|
|
# - Invalid model context limit
|
|
|
|
try:
|
|
client = HeadroomClient(
|
|
original_client=OpenAI(),
|
|
provider=OpenAIProvider(),
|
|
default_mode="invalid_mode", # Will raise ConfigurationError
|
|
)
|
|
except ConfigurationError as e:
|
|
print(f"Config error: {e}")
|
|
print(f"Field: {e.details.get('field')}")
|
|
```
|
|
|
|
### ProviderError
|
|
|
|
Raised for provider-specific issues.
|
|
|
|
```python
|
|
# Examples:
|
|
# - Unknown model name
|
|
# - Provider API error
|
|
# - Token counting failure
|
|
|
|
try:
|
|
response = client.chat.completions.create(
|
|
model="unknown-model-xyz",
|
|
messages=[...]
|
|
)
|
|
except ProviderError as e:
|
|
print(f"Provider error: {e}")
|
|
print(f"Provider: {e.details.get('provider')}")
|
|
```
|
|
|
|
### StorageError
|
|
|
|
Raised when database operations fail.
|
|
|
|
```python
|
|
# Examples:
|
|
# - Database connection failure
|
|
# - Write permission denied
|
|
# - Disk full
|
|
|
|
try:
|
|
metrics = client.get_metrics()
|
|
except StorageError as e:
|
|
print(f"Storage error: {e}")
|
|
# Application can continue - just won't have metrics
|
|
```
|
|
|
|
### CompressionError
|
|
|
|
Raised when compression fails (rare).
|
|
|
|
```python
|
|
# Examples:
|
|
# - Malformed JSON in tool output
|
|
# - Unexpected data structure
|
|
|
|
# Note: In practice, compression errors are caught internally
|
|
# and the original content passes through unchanged.
|
|
# This exception is only raised if you explicitly enable strict mode.
|
|
```
|
|
|
|
### ValidationError
|
|
|
|
Raised when setup validation fails.
|
|
|
|
```python
|
|
result = client.validate_setup()
|
|
if not result["valid"]:
|
|
raise ValidationError(
|
|
"Setup validation failed",
|
|
details={"issues": result["issues"]}
|
|
)
|
|
```
|
|
|
|
## Safety Guarantee
|
|
|
|
**If compression fails, the original content passes through unchanged.**
|
|
|
|
This is a core design principle. Your LLM calls never fail due to Headroom:
|
|
|
|
```python
|
|
# Even if SmartCrusher encounters unexpected data:
|
|
messages = [
|
|
{"role": "tool", "content": "malformed json {{{"}
|
|
]
|
|
|
|
# This will NOT raise an exception
|
|
# Instead, the malformed content passes through unchanged
|
|
response = client.chat.completions.create(
|
|
model="gpt-4o",
|
|
messages=messages
|
|
)
|
|
```
|
|
|
|
## Logging Errors
|
|
|
|
Enable logging to see error details:
|
|
|
|
```python
|
|
import logging
|
|
logging.basicConfig(level=logging.WARNING)
|
|
|
|
# Now you'll see warnings when compression is skipped:
|
|
# WARNING:headroom.transforms.smart_crusher:Skipping compression: invalid JSON
|
|
```
|
|
|
|
## Error Details
|
|
|
|
All Headroom exceptions include a `details` dict with context:
|
|
|
|
```python
|
|
try:
|
|
client = HeadroomClient(...)
|
|
except HeadroomError as e:
|
|
print(f"Error: {e}")
|
|
print(f"Type: {type(e).__name__}")
|
|
print(f"Details: {e.details}")
|
|
|
|
# Details might include:
|
|
# - field: which config field caused the error
|
|
# - provider: which provider was involved
|
|
# - model: which model was requested
|
|
# - original_error: underlying exception
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Catch Specific Exceptions
|
|
|
|
```python
|
|
# Good: catch specific exceptions
|
|
try:
|
|
response = client.chat.completions.create(...)
|
|
except ConfigurationError:
|
|
# Handle config issues
|
|
pass
|
|
except ProviderError:
|
|
# Handle provider issues
|
|
pass
|
|
|
|
# Avoid: catching all exceptions
|
|
try:
|
|
response = client.chat.completions.create(...)
|
|
except Exception:
|
|
# Too broad - might hide real bugs
|
|
pass
|
|
```
|
|
|
|
### 2. Let StorageError Pass
|
|
|
|
```python
|
|
# Storage errors don't affect core functionality
|
|
try:
|
|
metrics = client.get_metrics()
|
|
except StorageError:
|
|
metrics = [] # Continue without historical metrics
|
|
```
|
|
|
|
### 3. Validate on Startup
|
|
|
|
```python
|
|
client = HeadroomClient(...)
|
|
|
|
# Validate once at startup
|
|
result = client.validate_setup()
|
|
if not result["valid"]:
|
|
raise SystemExit(f"Headroom setup invalid: {result['issues']}")
|
|
|
|
# Then use client normally
|
|
response = client.chat.completions.create(...)
|
|
```
|
|
|
|
## Debugging
|
|
|
|
### Enable Debug Logging
|
|
|
|
```python
|
|
import logging
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
# Shows detailed transform decisions
|
|
# DEBUG:headroom.transforms.smart_crusher:Analyzing 1000 items...
|
|
# DEBUG:headroom.transforms.smart_crusher:Kept 15 items (errors: 2, anomalies: 3)
|
|
```
|
|
|
|
### Check Stats After Error
|
|
|
|
```python
|
|
try:
|
|
response = client.chat.completions.create(...)
|
|
except HeadroomError:
|
|
# Check what happened
|
|
stats = client.get_stats()
|
|
print(f"Last request stats: {stats}")
|
|
```
|