---
title: Error Handling Pattern
category: patterns
---
# Error Handling Pattern

## Rules

- Use explicit exceptions for domain/error classification (e.g., ProviderError, ValueError).
- Prefer logging.exception when catching an exception where stack trace is useful.
- Avoid broad except: clauses that swallow exceptions; if broad except is used for "best-effort" fallback, log at warning and include original exception context.
- For public library-like functions, prefer raising typed exceptions instead of returning magic values ([], False) — only return safe defaults where documented.

## Examples

### ai_provider.py - Network error to ProviderError

```python
except requests.ConnectionError as exc:
    if attempt == retries:
        raise ProviderError(
            f"Connection error when calling provider: {exc}"
        ) from exc
    ...
```

### pipeline/ai_provider_wrapper.py - Best-effort with logging

```python
except Exception:
    _logger.exception("Failed to append audit event for embedding failure")
results[j] = None
```

### similarity/compute.py - Defensive import handling

```python
try:
    import duckdb
except Exception:
    logger.exception("duckdb import failed; cannot load vectors")
    return 0
```

## Anti-Patterns

### Bad: Silent exception swallowing

```python
try:
    do_work()
except Exception:
    return []
# BAD: hides the root cause and returns an ambiguous default
```

**Remediation**: Narrow exception types or at minimum log.exception() and re-raise or convert to a domain error if truly handled.

### Bad: Mixing print() and logging

**Problem**: Mixing print() and logging for errors.

**Remediation**: Replace print() calls with logger.* calls; use structured logging configuration.
