In this lesson, you will learn how to build middleware that automatically decorates errors with request-specific metadata, ensuring your logs provide a complete picture of why an operation failed.
The Problem with Naked Errors
When an error reaches your global error-handling middleware, it often arrives as a generic Error object. While a stack trace is helpful, it frequently lacks the "who, what, and where" of the request lifecycle—such as the userId, correlationId, or the specific route path. Relying on developers to manually wrap every error with this context is prone to human error and code duplication.
Automating Context Injection
Instead of manual wrapping, we can use a centralized middleware pattern. By leveraging AsyncLocalStorage (or attaching context to the req object), we can create a decorator that automatically injects execution context into any error thrown during the request cycle.
Consider this robust approach using a centralized error decorator:
// Middleware to inject context
const injectErrorContext = (err, req, res, next) => {
if (!err.context) {
err.context = {
userId: req.user?.id,
correlationId: req.headers['x-correlation-id'],
path: req.path,
timestamp: new Date().toISOString()
};
}
next(err);
};
// Global error handler
app.use((err, req, res, next) => {
// Now we have access to the full context for logging
logger.error('Request failed', {
message: err.message,
...err.context
});
res.status(500).json({ error: 'Internal Server Error' });
});
Why This Matters
By implementing this injection at the middleware level, you treat context as a first-class citizen in your observability pipeline. When an exception occurs—whether it's a deep-seated database query failure or a validation error—your logging system will capture the correlationId and userId without the business logic ever needing to know those values exist. This transforms your logs from scattered, anonymous stack traces into a correlated map of your system’s state at the exact moment of failure, significantly reducing your Mean Time to Recovery (MTTR).
Key Takeaway: By injecting request context automatically via middleware, you decouple error reporting from business logic while ensuring every failure contains the vital metadata needed for rapid debugging.