Error Responses

setErrorHandler + httpErrors From @fastify/sensible

Error Responses

Customize the JSON error payload with setErrorHandler and raise structured errors using the httpErrors helper from @fastify/sensible.

4 min read Level 2/5 #fastify#errors#sensible
What you'll learn
  • Throw httpErrors.notFound and badRequest with messages
  • Set a global error handler for a consistent response shape
  • Map validation errors to a user-friendly format

Every API ends up with a custom error shape — RFC 7807 problem details, a JSON:API errors array, or a simple { code, message }. Fastify supplies the pieces; you wire them together.

Raising Errors

npm i @fastify/sensible
await app.register(import('@fastify/sensible'));

app.get('/posts/:id', async (req) => {
  const post = await db.posts.find(req.params.id);
  if (!post) throw app.httpErrors.notFound('No post with that id');
  return post;
});

The thrown error carries statusCode, error, and message — Fastify’s default handler turns that into a JSON body.

A Global Error Handler

app.setErrorHandler((err, req, reply) => {
  req.log.error({ err, reqId: req.id }, 'request failed');

  if (err.validation) {
    return reply.code(400).send({
      code: 'validation_failed',
      message: 'One or more fields are invalid',
      details: err.validation,
    });
  }

  const status = err.statusCode ?? 500;
  reply.code(status).send({
    code: status === 500 ? 'internal_error' : err.code ?? 'error',
    message: status === 500 ? 'Something went wrong' : err.message,
  });
});

Hide the message on 500s in production — surface stack traces only to your log aggregator.

404 Handler

setNotFoundHandler is the matching helper for unmatched routes:

app.setNotFoundHandler((req, reply) => {
  reply.code(404).send({ code: 'not_found', message: 'Route not found' });
});
Content-Types & Parsers →