Express — error handler never runs for thrown async errors
Fix Express error handling for async routes by forwarding errors to next or using an async wrapper.
Symptoms
- A rejected promise in a route does not trigger the error middleware
- The request hangs and no response is sent
- An Express 4 app ignores async thrown errors
- The process logs an unhandled rejection instead of using the error handler
Possible causes
- Express 4 does not catch promise rejections from async handlers automatically
- The handler throws inside an async function without try/catch or next
- The error middleware is registered before the routes
- An error is swallowed in a catch that does not rethrow or call next
Diagnosis steps
Check where the error middleware is registered
grep -n "app.use" server.jsInterpretation
Error middleware must be registered after the routes and take four arguments to be recognized as an error handler.
Confirm the async handler shape
grep -n "async (" routes/Interpretation
Async handlers that throw without forwarding leave the promise rejected and the middleware unaware.
Forward explicitly to next
try { await work() } catch (e) { next(e) }Interpretation
Calling next with the error routes it to the error middleware instead of leaving an unhandled rejection.
Root cause
Express 4 does not observe promise rejections from async handlers, so a thrown error never reaches the error middleware and the request is left unresolved.
Fix
Wrap async handlers so rejections call next, add a four-argument error middleware after the routes, and avoid swallowing errors without rethrowing or forwarding.
Verify the fix
Trigger the failing route and confirm the error middleware responds with the expected status, and confirm no unhandled rejection is logged.
Symptom walkthrough
An async route handler throws or rejects, yet the express error middleware never runs: the request hangs and the process logs an unhandled rejection instead. Express 4 does not await handler promises, so a rejection escapes the middleware chain. The error handler may also be misordered or lack the four-argument signature that marks it as an error handler.
Fix in practice
Forward every async error to next by wrapping handlers or catching and calling next(error). Register the error middleware after the routes with four parameters so Express recognizes it. Do not swallow errors in a catch that neither rethrows nor calls next.
Verification
Trigger the failing route and confirm the error middleware returns the expected status, then confirm no unhandled rejection appears in the logs. The middleware responding proves errors are being routed correctly.
Diagnostic commands
Check the behavior with commands like these:
grep -n "app.use" server.js
grep -n "async (" routes/
try { await work() } catch (e) { next(e) }