Errors

Errors

Table of contents

Error Handling In Node.js

Uncaught Errors

In Node.js, uncaught errors are likely to cause memory leaks, file descriptor leaks, and other major production issues. Domains were a failed attempt to fix this.

Given that it is not possible to process all uncaught errors sensibly, the best way to deal with them is to crash.

Catching Errors In Promises

If you are using promises, you should attach a .catch() handler synchronously.

Errors In Fastify

Fastify follows an all-or-nothing approach and aims to be lean and optimal as much as possible. The developer is responsible for making sure that the errors are handled properly.

Errors In Input Data

Most errors are a result of unexpected input data, so we recommend validating your input data against a JSON schema.

Catching Uncaught Errors In Fastify

Fastify tries to catch as many uncaught errors as it can without hindering performance. This includes:

  1. synchronous routes, e.g. app.get('/', () => { throw new Error('kaboom') })
  2. async routes, e.g. app.get('/', async () => { throw new Error('kaboom') })

The error in both cases will be caught safely and routed to Fastify’s default error handler for a generic 500 Internal Server Error response.

To customize this behavior you should use setErrorHandler.

Errors In Fastify Lifecycle Hooks And A Custom Error Handler

From the Hooks documentation:

If you get an error during the execution of your hook, just pass it to done() and Fastify will automatically close the request and send the appropriate error code to the user.

When a custom error handler has been defined through setErrorHandler, the custom error handler will receive the error passed to the done() callback (or through other supported automatic error handling mechanisms). If setErrorHandler has been used multiple times to define multiple handlers, the error will be routed to the most precedent handler defined within the error encapsulation context. Error handlers are fully encapsulated, so a setErrorHandler call within a plugin will limit the error handler to that plugin’s context.

The root error handler is Fastify’s generic error handler. This error handler will use the headers and status code in the Error object, if they exist. The headers and status code will not be automatically set if a custom error handler is provided.

Some things to consider in your custom error handler:

  • you can reply.send(data), which will behave as it would in regular route handlers

    • objects are serialized, triggering the preSerialization lifecycle hook if you have one defined
    • strings, buffers, and streams are sent to the client, with appropriate headers (no serialization)
  • You can throw a new error in your custom error handler - errors (new error or the received error parameter re-thrown) - will call the parent errorHandler.

    • onError hook will be triggered once only for the first error being thrown.
    • an error will not be triggered twice from a lifecycle hook - Fastify internally monitors the error invocation to avoid infinite loops for errors thrown in the reply phases of the lifecycle. (those after the route handler)

When utilizing Fastify’s custom error handling through setErrorHandler, you should be aware of how errors are propagated between custom and default error handlers.

If a plugin’s error handler re-throws an error, and the error is not an instance of Error (as seen in the /bad route in the following example), it will not propagate to the parent context error handler. Instead, it will be caught by the default error handler.

To ensure consistent error handling, it is recommended to throw instances of Error. For instance, in the following example, replacing throw 'foo' with throw new Error('foo') in the /bad route ensures that errors propagate through the custom error handling chain as intended. This practice helps avoid potential pitfalls when working with custom error handling in Fastify.

For example:

  1. const Fastify = require('fastify')
  2. // Instantiate the framework
  3. const fastify = Fastify({
  4. logger: true
  5. })
  6. // Register parent error handler
  7. fastify.setErrorHandler((error, request, reply) => {
  8. reply.status(500).send({ ok: false })
  9. })
  10. fastify.register((app, options, next) => {
  11. // Register child error handler
  12. fastify.setErrorHandler((error, request, reply) => {
  13. throw error
  14. })
  15. fastify.get('/bad', async () => {
  16. // Throws a non-Error type, 'bar'
  17. throw 'foo'
  18. })
  19. fastify.get('/good', async () => {
  20. // Throws an Error instance, 'bar'
  21. throw new Error('bar')
  22. })
  23. next()
  24. })
  25. // Run the server
  26. fastify.listen({ port: 3000 }, function (err, address) {
  27. if (err) {
  28. fastify.log.error(err)
  29. process.exit(1)
  30. }
  31. // Server is listening at ${address}
  32. })

Fastify Error Codes

You can access errorCodes for mapping:

  1. // ESM
  2. import { errorCodes } from 'fastify'
  3. // CommonJs
  4. const errorCodes = require('fastify').errorCodes

For example:

  1. const Fastify = require('fastify')
  2. // Instantiate the framework
  3. const fastify = Fastify({
  4. logger: true
  5. })
  6. // Declare a route
  7. fastify.get('/', function (request, reply) {
  8. reply.code('bad status code').send({ hello: 'world' })
  9. })
  10. fastify.setErrorHandler(function (error, request, reply) {
  11. if (error instanceof Fastify.errorCodes.FST_ERR_BAD_STATUS_CODE) {
  12. // Log error
  13. this.log.error(error)
  14. // Send error response
  15. reply.status(500).send({ ok: false })
  16. } else {
  17. // fastify will use parent error handler to handle this
  18. reply.send(error)
  19. }
  20. })
  21. // Run the server!
  22. fastify.listen({ port: 3000 }, function (err, address) {
  23. if (err) {
  24. fastify.log.error(err)
  25. process.exit(1)
  26. }
  27. // Server is now listening on ${address}
  28. })

Below is a table with all the error codes that Fastify uses.

CodeDescriptionHow to solveDiscussion
FST_ERR_NOT_FOUND404 Not Found-#1168
FST_ERR_OPTIONS_NOT_OBJFastify options wrongly specified.Fastify options should be an object.#4554
FST_ERR_QSP_NOT_FNQueryStringParser wrongly specified.QueryStringParser option should be a function.#4554
FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FNSchemaController.bucket wrongly specified.SchemaController.bucket option should be a function.#4554
FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FNSchemaErrorFormatter option wrongly specified.SchemaErrorFormatter option should be a non async function.#4554
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJajv.customOptions wrongly specified.ajv.customOptions option should be an object.#4554
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARRajv.plugins option wrongly specified.ajv.plugins option should be an array.#4554
FST_ERR_VERSION_CONSTRAINT_NOT_STRVersion constraint wrongly specified.Version constraint should be a string.#4554
FST_ERR_CTP_ALREADY_PRESENTThe parser for this content type was already registered.Use a different content type or delete the already registered parser.#1168
FST_ERR_CTP_INVALID_TYPEContent-Type wrongly specifiedThe Content-Type should be a string.#1168
FST_ERR_CTP_EMPTY_TYPEContent-Type is an empty string.Content-Type cannot be an empty string.#1168
FST_ERR_CTP_INVALID_HANDLERInvalid handler for the content type.Use a different handler.#1168
FST_ERR_CTP_INVALID_PARSE_TYPEThe provided parse type is not supported.Accepted values are string or buffer.#1168
FST_ERR_CTP_BODY_TOO_LARGEThe request body is larger than the provided limit.Increase the limit in the Fastify server instance setting: bodyLimit#1168
FST_ERR_CTP_INVALID_MEDIA_TYPEThe received media type is not supported (i.e. there is no suitable Content-Type parser for it).Use a different content type.#1168
FST_ERR_CTP_INVALID_CONTENT_LENGTHRequest body size did not match Content-Length.Check the request body size and the Content-Length header.#1168
FST_ERR_CTP_EMPTY_JSON_BODYBody cannot be empty when content-type is set to application/json.Check the request body.#1253
FST_ERR_CTP_INSTANCE_ALREADY_STARTEDFastify is already started.-#4554
FST_ERR_INSTANCE_ALREADY_LISTENINGFastify instance is already listening.-#4554
FST_ERR_DEC_ALREADY_PRESENTA decorator with the same name is already registered.Use a different decorator name.#1168
FST_ERR_DEC_DEPENDENCY_INVALID_TYPEThe dependencies of decorator must be of type Array.Use an array for the dependencies.#3090
FST_ERR_DEC_MISSING_DEPENDENCYThe decorator cannot be registered due to a missing dependency.Register the missing dependency.#1168
FST_ERR_DEC_AFTER_STARTThe decorator cannot be added after start.Add the decorator before starting the server.#2128
FST_ERR_HOOK_INVALID_TYPEThe hook name must be a string.Use a string for the hook name.#1168
FST_ERR_HOOK_INVALID_HANDLERThe hook callback must be a function.Use a function for the hook callback.#1168
FST_ERR_HOOK_INVALID_ASYNC_HANDLERAsync function has too many arguments. Async hooks should not use the done argument.Remove the done argument from the async hook.#4367
FST_ERR_HOOK_NOT_SUPPORTEDThe hook is not supported.Use a supported hook.#4554
FST_ERR_MISSING_MIDDLEWAREYou must register a plugin for handling middlewares, visit Middleware for more info.Register a plugin for handling middlewares.#2014
FST_ERR_HOOK_TIMEOUTA callback for a hook timed out.Increase the timeout for the hook.#3106
FST_ERR_LOG_INVALID_DESTINATIONThe logger does not accept the specified destination.Use a ‘stream’ or a ‘file’ as the destination.#1168
FST_ERR_LOG_INVALID_LOGGERThe logger should have all these methods: ‘info’, ‘error’, ‘debug’, ‘fatal’, ‘warn’, ‘trace’, ‘child’.Use a logger with all the required methods.#4520
FST_ERR_REP_INVALID_PAYLOAD_TYPEReply payload can be either a string or a Buffer.Use a string or a Buffer for the payload.#1168
FST_ERR_REP_RESPONSE_BODY_CONSUMEDUsing Response as reply payload, but the body is being consumed.Make sure you don’t consume the Response.body#5286
FST_ERR_REP_ALREADY_SENTA response was already sent.-#1336
FST_ERR_REP_SENT_VALUEThe only possible value for reply.sent is true.-#1336
FST_ERR_SEND_INSIDE_ONERRYou cannot use send inside the onError hook.-#1348
FST_ERR_SEND_UNDEFINED_ERRUndefined error has occurred.-#2074
FST_ERR_BAD_STATUS_CODEThe status code is not valid.Use a valid status code.#2082
FST_ERR_BAD_TRAILER_NAMECalled reply.trailer with an invalid header name.Use a valid header name.#3794
FST_ERR_BAD_TRAILER_VALUECalled reply.trailer with an invalid type. Expected a function.Use a function.#3794
FST_ERR_FAILED_ERROR_SERIALIZATIONFailed to serialize an error.-#4601
FST_ERR_MISSING_SERIALIZATION_FNMissing serialization function.Add a serialization function.#3970
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FNMissing Content-Type serialization function.Add a serialization function.#4264
FST_ERR_REQ_INVALID_VALIDATION_INVOCATIONInvalid validation invocation. Missing validation function for HTTP part nor schema provided.Add a validation function.#3970
FST_ERR_SCH_MISSING_IDThe schema provided does not have $id property.Add a $id property.#1168
FST_ERR_SCH_ALREADY_PRESENTA schema with the same $id already exists.Use a different $id.#1168
FST_ERR_SCH_CONTENT_MISSING_SCHEMAA schema is missing for the corresponding content type.Add a schema.#4264
FST_ERR_SCH_DUPLICATESchema with the same attribute already present!Use a different attribute.#1954
FST_ERR_SCH_VALIDATION_BUILDThe JSON schema provided for validation to a route is not valid.Fix the JSON schema.#2023
FST_ERR_SCH_SERIALIZATION_BUILDThe JSON schema provided for serialization of a route response is not valid.Fix the JSON schema.#2023
FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XXResponse schemas should be nested under a valid status code (2XX).Use a valid status code.#4554
FST_ERR_HTTP2_INVALID_VERSIONHTTP2 is available only from node >= 8.8.1.Use a higher version of node.#1346
FST_ERR_INIT_OPTS_INVALIDInvalid initialization options.Use valid initialization options.#1471
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLECannot set forceCloseConnections to idle as your HTTP server does not support closeIdleConnections method.Use a different value for forceCloseConnections.#3925
FST_ERR_DUPLICATED_ROUTEThe HTTP method already has a registered controller for that URL.Use a different URL or register the controller for another HTTP method.#2954
FST_ERR_BAD_URLThe router received an invalid URL.Use a valid URL.#2106
FST_ERR_ASYNC_CONSTRAINTThe router received an error when using asynchronous constraints.-#4323
FST_ERR_DEFAULT_ROUTE_INVALID_TYPEThe defaultRoute type should be a function.Use a function for the defaultRoute.#2733
FST_ERR_INVALID_URLURL must be a string.Use a string for the URL.#3653
FST_ERR_ROUTE_OPTIONS_NOT_OBJOptions for the route must be an object.Use an object for the route options.#4554
FST_ERR_ROUTE_DUPLICATED_HANDLERDuplicate handler for the route is not allowed.Use a different handler.#4554
FST_ERR_ROUTE_HANDLER_NOT_FNHandler for the route must be a function.Use a function for the handler.#4554
FST_ERR_ROUTE_MISSING_HANDLERMissing handler function for the route.Add a handler function.#4554
FST_ERR_ROUTE_METHOD_INVALIDMethod is not a valid value.Use a valid value for the method.#4750
FST_ERR_ROUTE_METHOD_NOT_SUPPORTEDMethod is not supported for the route.Use a supported method.#4554
FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTEDBody validation schema route is not supported.Use a different different method for the route.#4554
FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INTbodyLimit option must be an integer.Use an integer for the bodyLimit option.#4554
FST_ERR_ROUTE_REWRITE_NOT_STRrewriteUrl needs to be of type string.Use a string for the rewriteUrl.#4554
FST_ERR_REOPENED_CLOSE_SERVERFastify has already been closed and cannot be reopened.-#2415
FST_ERR_REOPENED_SERVERFastify is already listening.-#2415
FST_ERR_PLUGIN_VERSION_MISMATCHInstalled Fastify plugin mismatched expected version.Use a compatible version of the plugin.#2549
FST_ERR_PLUGIN_CALLBACK_NOT_FNCallback for a hook is not a function.Use a function for the callback.#3106
FST_ERR_PLUGIN_NOT_VALIDPlugin must be a function or a promise.Use a function or a promise for the plugin.#3106
FST_ERR_ROOT_PLG_BOOTEDRoot plugin has already booted.-#3106
FST_ERR_PARENT_PLUGIN_BOOTEDImpossible to load plugin because the parent (mapped directly from avvio)-#3106
FST_ERR_PLUGIN_TIMEOUTPlugin did not start in time.Increase the timeout for the plugin.#3106
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCEThe decorator is not present in the instance.-#4554
FST_ERR_VALIDATIONThe Request failed the payload validation.Check the request payload.#4824
FST_ERR_LISTEN_OPTIONS_INVALIDInvalid listen options.Check the listen options.#4886
FST_ERR_ERROR_HANDLER_NOT_FNError Handler must be a functionProvide a function to setErrorHandler.#5317