5.4 KiB
name, description
| name | description |
|---|---|
| error-handling | Use when writing try/catch blocks, creating custom error classes, implementing retry logic, designing error boundaries in React, building API error responses, or handling failures gracefully. Also activate for any code dealing with exceptions, error propagation, graceful degradation, or fault tolerance. |
Error Handling Patterns
When to Use
- Building API endpoints that must return consistent error responses
- Creating custom exception hierarchies for a domain model
- Implementing retry logic for unreliable network calls or external services
- Designing React error boundaries for component-level fault isolation
- Wrapping third-party libraries that throw unpredictable errors
- Converting between error representations at architectural boundaries (e.g., domain errors to HTTP errors)
- Adopting the Result pattern to avoid exceptions for expected failure paths
When NOT to Use
- Simple one-off scripts or throwaway prototypes where unhandled crashes are acceptable
- Configuration files, static data, or declarative markup with no runtime logic
- Pure data transformation functions where invalid input should be prevented by types, not caught at runtime
Quick Reference
| Pattern | Description |
|---|---|
| Custom Error Classes | Domain-specific error hierarchy with error codes, messages, and detail metadata |
| Error Boundaries (React) | Component-level fault isolation using react-error-boundary or class-based boundaries |
| Retry with Backoff | Exponential backoff + jitter decorator/wrapper for transient failures |
| Circuit Breaker | Short-circuit calls to unhealthy dependencies, fall back to degraded state |
| Feature-Flag Degradation | Graceful UI/service degradation controlled by feature flags |
| API Error Responses | Consistent RFC 7807 Problem Details payloads with global exception handlers |
| Error Logging | Structured context (request ID, error code, stack trace) for observability |
| Result Pattern | Discriminated union / Result type for expected failure paths without exceptions |
Language References
See references/python-patterns.md for Python examples.
See references/typescript-patterns.md for TypeScript/React examples.
Best Practices
-
Catch specific exceptions, not bare
exceptorcatch. A catch-all hides bugs. Catch only the errors you know how to handle and let everything else propagate. -
Translate errors at architectural boundaries. A database
IntegrityErrorshould become a domainDuplicateEntryErrorat the repository layer, then an HTTP 409 at the API layer. Each layer speaks its own error language. -
Preserve the original cause. Always chain the original exception (
raise X from originalin Python,{ cause }in TypeScript) so the root cause is visible in logs and debuggers. -
Fail fast, recover high. Detect errors as early as possible (validate inputs at the boundary) but handle them at the highest level that has enough context to decide what to do (e.g., return an HTTP response, show a fallback UI).
-
Never swallow errors silently. An empty
except: passorcatch {}is almost always a bug. At minimum, log the error. If you intentionally ignore it, leave a comment explaining why. -
Use the Result pattern for expected failures. When a function can legitimately fail (parsing, validation, lookups), return a Result instead of throwing. Reserve exceptions for truly unexpected situations.
-
Make errors actionable. Every error message should help the reader fix the problem. Include what happened, what was expected, and what the caller can do about it.
"User not found"is worse than"User with id '123' not found. Verify the id and check that the user has not been deleted.". -
Test the error paths. Write explicit tests for every error branch. Verify the error type, message, and status code. Error paths that are never tested are error paths that will break in production.
Common Pitfalls
-
Catching too broadly. Using
except Exceptionorcatch (e: any)silences programming errors likeTypeErrororReferenceErrorthat should crash loudly during development. -
Logging and re-throwing without deduplication. If every layer logs the same error, you get five log entries for one failure. Log at the outermost handler and let inner layers propagate.
-
Returning error data in the wrong shape. Mixing
{ error: "..." },{ message: "..." }, and{ errors: [...] }across endpoints forces every client to handle multiple formats. Pick one shape and enforce it globally. -
Leaking internal details to clients. Stack traces, database table names, and file paths in API responses are a security risk. Sanitize errors before they leave the server.
-
Retrying non-idempotent operations. Retrying a
POST /ordersthat partially succeeded can create duplicate orders. Only retry operations that are safe to repeat, or use idempotency keys. -
Ignoring async error boundaries. In React, error boundaries do not catch errors inside event handlers or async callbacks. Use try/catch inside
onClick,useEffectcleanup, and promise chains separately.
Related Skills
logging- Structured logging setup and conventionsapi-client- HTTP client wrappers with built-in error handlingowasp- Preventing information leakage through error messagespython- Python exception syntax and idiomstypescript- TypeScript error types and narrowing