Unhandled errors crash servers. Express has a special four-argument error middleware: (err, req, res, next).
// Register after all routes
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).json({ error: err.message })
})Throwing errors in async routes
You must catch async errors and pass them to next():
app.get('/data', async (req, res, next) => {
try {
const data = await fetchSomething()
res.json(data)
} catch (err) {
next(err) // passes to error handler
}
})Custom error classes
class AppError extends Error {
constructor(message, statusCode) {
super(message)
this.statusCode = statusCode
}
}
// ...GET /safe — responds { "ok": true }GET /crash — throws new Error("Something broke"){ "error": <message> } with status 500"Error handling demo ready" on start then close.Unhandled errors crash servers. Express has a special four-argument error middleware: (err, req, res, next).
// Register after all routes
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).json({ error: err.message })
})Throwing errors in async routes
You must catch async errors and pass them to next():
app.get('/data', async (req, res, next) => {
try {
const data = await fetchSomething()
res.json(data)
} catch (err) {
next(err) // passes to error handler
}
})Custom error classes
class AppError extends Error {
constructor(message, statusCode) {
super(message)
this.statusCode = statusCode
}
}
// ...GET /safe — responds { "ok": true }GET /crash — throws new Error("Something broke"){ "error": <message> } with status 500"Error handling demo ready" on start then close.