> Common Error Handling
Cross-cutting standards for error design, response shapes, error codes, and boundary placement. Use when handling errors, designing exception flows, or standardizing error responses.
curl "https://skillshub.wtf/HoangNguyen0403/agent-skills-standard/error-handling?format=md"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.
> related_skills --same-repo
> typescript-tooling
Development tools, linting, and build config for TypeScript. Use when configuring ESLint, Prettier, Jest, Vitest, tsconfig, or any TS build tooling. (triggers: tsconfig.json, .eslintrc.*, jest.config.*, package.json, eslint, prettier, jest, vitest, build, compile, lint)
> typescript-security
Secure coding practices for TypeScript. Use when validating input, handling auth tokens, sanitizing data, or managing secrets and sensitive configuration. (triggers: **/*.ts, **/*.tsx, validate, sanitize, xss, injection, auth, password, secret, token)
> typescript-language
Modern TypeScript standards for type safety and maintainability. Use when working with types, interfaces, generics, enums, unions, or tsconfig settings. (triggers: **/*.ts, **/*.tsx, tsconfig.json, type, interface, generic, enum, union, intersection, readonly, const, namespace)
> typescript-best-practices
Idiomatic TypeScript patterns for clean, maintainable code. Use when writing or refactoring TypeScript classes, functions, modules, or async logic. (triggers: **/*.ts, **/*.tsx, class, function, module, import, export, async, promise)