Koa implements a default error handler, which works well for many situations. It is essentially middleware with a try...catch statement defined at the very top of the Koa middleware stack. If no other error handler is defined, all errors thrown when the application is running will flow into Koa's default error handler.
The default handler uses the status code of err.status when available, else it uses 500 (for Internal Server Error). It also sends back err.message as the response if err.expose is set to true.
If err.expose is set to false, then it generates a message from the error code of the error thrown. For example, for the 400 Bad Request error, the message generated will be Invalid Request.
When sending back a response, the default error handler clears all headers, except for the ones present in err.headers. We can set headers for errors using a try... catch statement in another middleware, as seen here:
app.use(async (ctx, next) => {
try {
await next();
} catch(err) {
if (err.status === 503) {
err.headers = Object.assign({}, err.headers, {
'Retry-After': 30
});
}
throw err;
}
});
The preceding code shows how we set the Retry-After header value for 503 Service Unavailable errors.
When an error occurs, and it is still possible to respond back to the client (no data has been written to the socket), as expected, Koa responds with 500 Internal Server Error. Either way, the error event is still emitted.