DEV Community

Cover image for Fastify Error handlers
Manuel Spigolon
Manuel Spigolon

Posted on • Edited on

Fastify Error handlers

All you need to know to control the Fastify errors!

Error types

Errors in the Fastify world could be grouped in:

  1. Startup errors are triggered when the application starts and the server won't start
  2. Runtime errors happen when the server receives an HTTP call and the server will remain up&running:
    1. Application errors are throws by the developer when the business logic need it
    2. Unexpected errors are throws when there is a bug
    3. Validation errors appear when the submitted data from a client doesn't match the endpoint's JSON schema
    4. 404 errors when the requested route doesn't exist

Manage Runtime errors

Let's deep dive into the most interesting kinds of errors: handler's error.
During your application lifecycle, it is necessary to validate user input, check data consistency and so on.

So manage errors is a key feature that Fastify support through these options:

As we see, Fastify has a lot of tools that can work together to archive all your need to reply with clear errors!

The first aspect to explain is the difference between:

  • throwing an Error: this happens when an Error instance is processed
  • sending a JSON error: this happens when an HTTP status code >= 300 is set and a JSON is processed
  • unexpected exception: this happens due to nasty bug, don't worry, Fastify will handle it for you!

Here a code example in a sync and async handler:

function callbackStyleHandler (request, reply) {
  // "throwing" an error
  reply.send(new Error('foo bar error'))
  // ...or sending a json error
  reply.code(500).send({ message: 'foo bar error' })
  // ...or unexpected exception
  'this is not an array'.sort() // fastify will handle the TypeError for you
}

async function asyncHandler (request, reply) {
  // "throwing" an error
  throw new Error('foo bar error')
  // ...or sending a json error
  reply.code(500)
  return { message: 'foo bar error' }
  // ...or unexpected exception
  'this is not an array'.sort() // fastify will handle the TypeError for you
}
Enter fullscreen mode Exit fullscreen mode

So, based on what you are sending (in sync handlers) or returning (in async handler), the send lifecycle will act like this:

                 ★ schema validation Error
                             │
                             └─▶ schemaErrorFormatter
                                        │
                   reply sent ◀── JSON ─┴─ Error instance
                                                │
                                                │         ★ throw an Error
               ★ send or return                 │                 │
                      │                         ▼                 │
 reply sent ◀── JSON ─┴─ Error instance ──▶ setErrorHandler ◀─────┘
                                                │
                           reply sent ◀── JSON ─┴─ Error instance ──▶ onError Hook
                                                                         │
                                                                         └─▶ reply sent
Enter fullscreen mode Exit fullscreen mode

So, sending a JSON error will not execute the error handler and the onError hooks too.
What your functions return may impact the execution of your code!

Every component of this flow can be customized for every route!!
Thanks to all the route options you can
add some route customization when needed that will overwrite the default setting in the fastify instance.

Notice that in async handler returns an Error or throws it is the same:

throw new Error('foo bar error')
// it is like
return new Error('foo bar error')
Enter fullscreen mode Exit fullscreen mode

You can find a complete code example that replicates that reply.send flow at github.com/Eomm/fastify-discord-bot-demo

Manage Startup errors

These kind of errors are the most common at the beginning of a new application.
They can be triggered by:

  • plugins that don't start due to an error, like a failed DB connection
  • plugins that don't start in time, like a pre-fetch to a slow endpoint
  • bad usages of the Fastify framework, like defining 2 routes with the same path

To manage these errors you have to check the listen or the ready results:

fastify.register((instance, ops, next) => {
  next(new Error('this plugin failed to load'))
})

fastify.listen(8080, (err) => {
  if (err) {
    // startup error
    fastify.log.fatal(err)
    process.exit(1)
  }
})
Enter fullscreen mode Exit fullscreen mode

Instead, if you want to ignore the error throws by one plugin (it should not, but Fastify lets you free to do what you want with your application)
you can manage it like this and the server will start as expected.

fastify.register((instance, ops, next) => {
  next(new Error('this plugin failed to load'))
}).after(err => {
  fastify.log.warn(err, 'Ops, my plugin fail to load, but nevermind')
})
Enter fullscreen mode Exit fullscreen mode

Now, let's assume that the plugin may throw two errors: one you can ignore and one cannot be ignored:

fastify.register((instance, ops, next) => {
  if (condition) {
    next(new Error('cannot be ignored'))
  } else {
    next(new Error('can be ignored'))
  }
}).after((err, instance, next) => {
  if (err.message === 'cannot be ignored') {
    next(err)
  } else {
    fastify.log.warn(err, 'Ops, my plugin fail to load, but nevermind')
    next()
  }
})
Enter fullscreen mode Exit fullscreen mode

Timeout

As said, the plugin has a maximum amount of time to start correctly.
To customize this timeout you can set the pluginTimeout option:

const fastify = Fastify({
  pluginTimeout: 100000, // millisec
  logger: true
})
Enter fullscreen mode Exit fullscreen mode

End

Now, I hope I have been teaching you about all you need to know to manage the application errors in your Fastify server!
For more Fastify content follow me on twitter!

Write comments here below or open an issue on GitHub for any questions or feedback!
Thank you for reading!

Acknowledgements

Thank you very much to Alona for the great feedback!
Image post credits to xkcd (CC BY-NC 2.5)

Top comments (1)

Collapse
 
k_penguin_sato profile image
K-Sato

I'm new to Fastify and this was exactly what I was looking for!
Thank you!