common-error-handling
maintained by HoangNguyen0403
star
305
account_tree
90
verified_user
MIT License
name: Common Error Handling description: Cross-cutting standards for error design, response shapes, error codes, and boundary placement. Use when handling errors, designing exception flows, or standardizing error responses. metadata: labels: [error-handling, exceptions, resilience, api-errors] triggers: files: [ '/*.service.ts', '/.handler.ts', '**/.controller.ts', '/*.go', '/.java', '**/.kt', '**/*.py', ] keywords: [ 'error handling', exception, 'try catch', 'error boundary', 'error response', 'error code', throw, Result, ]
Common Error Handling Standards
Priority: P1 (OPERATIONAL)
Consistent, predictable error handling is the backbone of maintainable systems. Errors are first-class citizens — design them explicitly.
🏗 Error Response Shape (HTTP APIs)
All API errors MUST use a consistent envelope:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "The requested user does not exist.",
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"details": []
}
}
| Field | Rule |
|---|---|
code |
SCREAMING_SNAKE_CASE machine-readable code. Never localize. |
message |
Human-readable English summary. Safe for end-users (no stack traces). |
traceId |
Correlation ID from the request context. |
details |
Optional array of field-level validation errors. Empty for non-validation errors. |
🗂 Error Classification
| Layer | Error Type | Strategy |
|---|---|---|
| Validation | 400 Bad Request |
Return details[] with field paths |
| Authentication | 401 Unauthorized |
Generic message — never expose reason |
| Authorization | 403 Forbidden |
Log attempt, never expose role info |
| Not Found | 404 Not Found |
Distinguishable from auth errors |
| Conflict | 409 Conflict |
Include conflicting resource ID |
| Unhandled | 500 Internal Server Error |
Log full context, return generic message |
📦 Error Wrapping vs Replacement
-
Wrap when adding context:
fmt.Errorf("processOrder: %w", err)(Go) /new ServiceError('msg', { cause: err })(JS). - Replace only when the original error leaks sensitive internal details.
- Never swallow: Catch without logging or re-throwing hides bugs — forbidden.
🛡 Boundary Placement
- API Layer: Translate domain/infrastructure errors into HTTP responses. Use a global exception filter/middleware.
-
Domain Layer: Throw domain-specific errors (e.g.,
InsufficientStockError). Never reference HTTP status codes. -
Infrastructure Layer: Throw infrastructure errors (e.g.,
DatabaseConnectionError). Wrap 3rd party exceptions. - Never: Let infrastructure errors (raw DB/network exceptions) bubble up to the API response.
Request → [API Layer: maps to HTTP] → [Domain: business errors] → [Infra: DB/network errors]
🔢 Error Code Design
- Codes are permanent IDs — treat them like API contracts. Once published, never rename.
- Format:
<DOMAIN>_<NOUN>_<VERB>→ORDER_PAYMENT_FAILED,USER_EMAIL_DUPLICATE. - Define in a centralized constants file; never inline magic strings.
Anti-Patterns
-
No
catch(e) {}: Always log or re-throw. - No stack traces in responses: Leak internal structure to attackers.
-
No generic
500for validation: Use400withdetails. - No HTTP status codes in domain layer: Domain errors are business concepts, not transport decisions.
- No error-code proliferation: Prefer a small, well-documented set over one code per exception class.
chat Comments (0)
Sign in to join the discussion and leave a comment.
Skill Details
GitHub Stars
305
GitHub Forks
90
Created
Mar 2026
Last Updated
5个月前
development
development architecture patterns
Related Skills
Build your own?
Join 12,000+ developers contributing to the Claude ecosystem.
No comments yet. Be the first to share your thoughts!