| name | error-handling-architecture |
| description | When designing how a system recovers from and reports failures. |
| version | 2.0.0 |
| category | backend |
| tags | ["backend","errors","resilience","error-handling"] |
| skill_type | architecture |
| author | skiLLM |
| license | MIT |
| compatible_agents | ["claude-code","cursor","copilot","codex"] |
| estimated_context_tokens | 1700 |
| dangerous | false |
| requires_review | false |
| security_level | review-required |
| dependencies | ["api-design-rest"] |
| triggers | ["error","exception","try-catch","error-handling","failure"] |
| permissions | {"filesystem":{"read":true,"write":true},"network":{"outbound":false},"shell":{"execute":false}} |
| input_requirements | ["existing backend service","framework setup"] |
| output_contract | ["standardized error responses","no sensitive data leaked","proper logging"] |
| failure_conditions | ["silent exception catching","returning 200 for errors","leaking database details"] |
| last_updated | "2026-05-15T00:00:00.000Z" |
Error Handling Architecture
Purpose
Uncaught exceptions crash servers. Leaked errors expose vulnerabilities. This skill creates a central, robust pipeline for capturing, categorizing, logging, and responding to failures without leaking sensitive data, ensuring system resilience and debugging capability.
When to use
- Setting up a new backend service
- Refactoring code with excessive uncoordinated
try/catch blocks
- Standardizing API error responses across a team
- Implementing a new microservice with shared error handling
When NOT to use
- Client-side error handling (different context)
- Monitoring/alerting setup (separate concern, use Logging & Observability instead)
- Specific framework error documentation
Inputs required
- Existing backend service codebase
- Framework error handling capabilities (Express middleware, Django signals, etc.)
- Logging infrastructure setup
Workflow
- Define Error Classes: Create base
AppError class with statusCode, isOperational flag, and metadata
- Categorize Errors: Distinguish Operational (bad input, network) from Programmer (null ptr, logic bug)
- Centralize Middleware: Add framework-level error handler to catch ALL exceptions globally
- Log Appropriately: Full stack for 5xx errors; metadata only for 4xx errors
- Sanitize Output: Strip stack traces and internal details before sending to client
- Crash on Programmer Error: Unhandled programmer errors MUST crash and restart the process
- Test Error Paths: Verify error handling works for all failure scenarios
Rules
- MUST NEVER silently swallow exceptions (
catch(e) {})
- MUST crash and restart process for unhandled Programmer Errors
- MUST standardize all HTTP error responses to RFC 7807 format
- MUST log full stack traces for 5xx errors
- MUST log only message and context for 4xx errors
- MUST sanitize all error responses (no DB details, SQL, stack traces)
- MUST NEVER throw string literals (always throw Error objects)
- MUST distinguish between Operational and Programmer errors
Anti-patterns
- Throwing Strings:
throw "User not found" (throw Error objects always)
- Leaking DB Details: Sending raw SQL constraint violation messages to client
- Silent Catching:
catch(e) {} with no logging or action
- 200 OK for Errors: HTTP 200 with
{ error: true } payload
- Generic Messages: "Something went wrong" (unhelpful for debugging)
- Unhandled Promises: Async functions without catch handlers
Failure conditions
- Unhandled exception occurs (process crashes without logging)
- Error response includes stack trace or internal details
- Silent exception swallowing (error never logged)
- HTTP 200 returned for failed requests
- Database constraint violation message sent to client
Validation checklist
Output format
- Error Object: Contains
statusCode, message, isOperational flag, and optional context
- Response Format: RFC 7807 Problem Details JSON
- Log Format: Structured JSON with timestamp, level, context, stack trace (for 5xx)
- Process Behavior: Unhandled programmer errors crash; operational errors continue
Security considerations
- Error messages MUST NOT leak internal architecture (DB names, file paths, versions)
- Stack traces MUST NEVER be sent to clients (log internally only)
- Database error messages MUST be wrapped (never expose raw constraints)
- Sensitive user data MUST NOT appear in error logs (sanitize before logging)
- Error pages MUST NOT reveal system information
Agent execution notes
- Agent MAY: Create error classes, add global error middleware, sanitize responses, implement error logging
- Agent MUST NEVER: Throw strings, catch exceptions silently, leak stack traces, return 200 for errors
- Agent MUST ASK: Before changing error categorization, before modifying global error handler
- Agent MUST VALIDATE: All errors are Error objects, no stack traces in responses, proper categorization
Example
❌ Anti-pattern (Silent catching, leaking details, wrong status):
app.get('/users/:id', async (req, res) => {
try {
const user = await db.query(`SELECT * FROM users WHERE id = ${req.params.id}`);
res.json(user);
} catch(e) {
res.json({ status: 'error', message: e.message });
}
});
✅ Correct pattern (Centralized, sanitized, proper codes):
class AppError extends Error {
constructor(statusCode, message, isOperational = true) {
super(message);
this.statusCode = statusCode;
this.isOperational = isOperational;
}
}
app.get('/users/:id', async (req, res, next) => {
try {
const user = await db.query('SELECT * FROM users WHERE id = ?', [req.params.id]);
if (!user) {
return next(new AppError(404, 'User not found'));
}
res.json(user);
} catch (err) {
next(err);
}
});
app.use((err, req, res, next) => {
logger[err.isOperational ? 'warn' : 'error']({
message: err.message,
statusCode: err.statusCode,
stack: err.stack,
requestId: req.id,
userId: req.user?.id
});
if (!err.isOperational) {
process.exit(1);
}
res.status(err.statusCode || 500).json({
type: 'https://api.example.com/errors/app-error',
title: err.statusCode === 404 ? 'Not Found' : 'Server Error',
detail: err.isOperational ? err.message : 'Internal server error',
status: err.statusCode || 500
});
});