principle-error-handlinglisted
Install: claude install-skill lugassawan/swe-workbench
# Error Handling
Errors are part of the contract. Handling them is not defensive programming — it is the design.
## Errors as Values vs Exceptions
Use the language's native error style; don't fight it.
- **Go** `error` values, **Rust** `Result<T, E>`, **TypeScript** typed unions: errors are explicit return paths, visible in signatures, handled by callers.
- Exceptions (Java, Python, C#) work best for truly unexpected conditions — programmer errors, not business failures.
- Reserve `panic` / `throw` / unchecked exceptions for unrecoverable programmer errors. Expected failures (network timeout, not found) must be value-level errors.
## Classify Before Handling
Not all errors deserve the same response.
- **Transient** — network blip, timeout, lock contention: retry with backoff (fail soft — degrade gracefully while recovering).
- **Permanent** — bad input, not found, permission denied: fail fast — surface immediately to the caller, never retry.
- **Programmer** — nil deref, index out of bounds, invariant violated: panic/crash, fix the code.
- Misclassifying a permanent error as transient wastes retry budget and delays the caller.
## Wrap, Don't Swallow
At each layer boundary, add context to the error and preserve the original cause for downstream inspection.
- Go: `fmt.Errorf("loading user config: %w", err)` — `%w` preserves `errors.Is` / `errors.As` traversal.
- Rust: `anyhow::Context` / `.with_context(|| ...)` — attach human-readable context without losing the source.
-