# Error Handling

> Design robust error handling that fails gracefully and aids debugging.

## When to Use
- Writing any code that interacts with external systems
- Reviewing error handling in existing code
- "Add error handling" / "make this more robust"

## Principles
1. **Fail fast, fail loud** — detect errors early and surface them clearly
2. **Handle specific exceptions** — never bare `except:` or `except Exception:`
3. **Preserve context** — include the original error in re-raised exceptions
4. **Log before handling** — log the error with context, then handle it
5. **Graceful degradation** — if a feature fails, don't crash the whole system
6. **User-facing errors are different from developer errors** — users get "Something went wrong, try again." Developers get stack traces.

## Pattern
```python
try:
    result = external_api_call(params)
except ConnectionError as e:
    logger.error("API connection failed: %s (params: %s)", e, params)
    return fallback_result()  # graceful degradation
except ValueError as e:
    logger.warning("Invalid response from API: %s", e)
    raise InvalidApiResponse(f"Unexpected response format: {e}") from e
except Exception as e:
    logger.exception("Unexpected error in API call")
    raise  # re-raise unexpected errors — don't swallow them
```

## Common Mistakes
- Swallowing exceptions silently (`except: pass`)
- Catching too broadly (`except Exception`) hiding real bugs
- Not logging enough context (what were the inputs? what was the state?)
- Retry without backoff — hammering a failing service makes it worse
