Profiles·Public

fastify

semver>=5.0.0 <6.0.0postconditions23functions10last verified2026-06-18coverage score91%

Postconditions — what we check

  • get · route-handler-timeout
    info
    Whenroute handler does not send a response within handlerTimeout milliseconds (when handlerTimeout > 0 is configured at server or route level)
    ThrowsFST_ERR_HANDLER_TIMEOUT — 503 Service Unavailable sent through error handler. Handler async work continues running unless request.signal is monitored.
    Required handlingUse request.signal for cooperative cancellation: pass it to fetch(), database queries, and stream.pipeline() so async work stops when the timeout fires. Override FST_ERR_HANDLER_TIMEOUT in setErrorHandler or route-level errorHandler to return 504 instead of 503 for downstream timeouts. Without signal monitoring, background work leaks resources after the client receives the 503.
    costmediumin proddegraded serviceusers seeservice unavailablevisibilityvisible
    Sources[1][2]
  • listen · listen-port-in-use
    error
    Whenport is already bound by another process (listen() called on occupied port)
    ThrowsError with code EADDRINUSE — Node.js system error
    Required handlingAwait listen() in try-catch. On EADDRINUSE, either use a different port or check that previous server instances were properly closed before restarting. Port 0 picks a random available port as an alternative.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][3]
  • listen · listen-plugin-timeout
    error
    Whenregistered plugins do not call done() / resolve their promises within pluginTimeout ms (default 10000ms) before listen() completes initialization
    ThrowsError with code ERR_AVVIO_PLUGIN_TIMEOUT — thrown by fastify's avvio plugin system
    Required handlingAwait listen() in try-catch. Ensure all plugins call their done callback or resolve async. Set pluginTimeout option higher if plugins legitimately take longer (e.g., database connection pools). Log error and exit process cleanly on failure.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][4]
  • listen · listen-container-binding
    warning
    Whenserver needs to be reachable from outside its container/VM but listen() is called with '127.0.0.1' (localhost-only)
    ThrowsNo error thrown — server starts successfully but is unreachable externally; requests silently time out
    Required handlingIn containerized environments (Docker, Kubernetes, AWS ECS), call listen({ port: 3000, host: '0.0.0.0' }) to bind all interfaces. '127.0.0.1' is correct only for development where external access is not needed.
    costhighin prodsilent failureusers seeservice unavailablevisibilitysilent
    Sources[5][1]
  • close · close-websocket-connection-leak
    error
    Whenserver has active WebSocket or HTTP upgrade connections when close() is called
    Throwsclose() hangs indefinitely — upgraded connections are not tracked by fastify's connection counter and prevent shutdown from completing
    Required handlingTrack WebSocket connections manually. In an 'onClose' hook or preClose handler, explicitly call ws.terminate() on all active WebSocket clients before awaiting close(). Without this, process.exit() may be required to force shutdown, risking data loss.
    costmediumin proddegraded serviceusers seeservice unavailablevisibilitysilent
    Sources[1][6]
  • close · close-hook-error
    warning
    Whenan onClose or preClose lifecycle hook throws or rejects during server shutdown
    ThrowsError from the hook propagates as close() promise rejection
    Required handlingAwait close() in try-catch. Log shutdown errors but still proceed with cleanup. Use finally block to ensure any remaining cleanup code runs even if a hook fails.
    costmediumin proddegraded serviceusers seeservice unavailablevisibilitysilent
    Sources[7]
  • ready · ready-plugin-timeout
    error
    Whena registered plugin does not call done() or resolve its async function within pluginTimeout ms (default 10000ms)
    ThrowsError with code ERR_AVVIO_PLUGIN_TIMEOUT — thrown by avvio, fastify's plugin loading system
    Required handlingAwait ready() in try-catch. Identify the slow plugin by checking the error message which includes the plugin name. Fix the plugin to complete initialization or increase pluginTimeout in fastify options. Log the error with full stack trace for debugging.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][8]
  • ready · ready-plugin-init-error
    error
    Whena plugin's async initializer rejects with an error (e.g., database connection fails during plugin setup)
    ThrowsThe plugin's error propagates through ready() promise rejection
    Required handlingAwait ready() in try-catch. Handle initialization failures explicitly — log details, emit alerts, and exit process with non-zero code so process managers (systemd, k8s, Docker) restart the service.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • register · register-errors-deferred-to-ready
    info
    Whena plugin's async initializer throws or rejects (database connection, external service registration failure, missing configuration)
    ThrowsError is NOT thrown at register() call time — it defers and surfaces when ready() or listen() is awaited
    Required handlingAlways await ready() or listen() in try-catch after all register() calls. Do not assume that a synchronous register() call means the plugin loaded successfully. Plugin initialization errors will only surface asynchronously.
    costhighin proddelayed failureusers seeservice unavailablevisibilityvisible
    Sources[9][1]
  • register · register-plugin-timeout
    info
    Whenplugin async initializer takes longer than pluginTimeout (default 10000ms) to call done() or resolve
    ThrowsError with code ERR_AVVIO_PLUGIN_TIMEOUT — surfaces at ready() or listen(), not at register()
    Required handlingUse fp-options or fastify-plugin options to set a per-plugin timeout, or increase global pluginTimeout. Ensure async plugin inits complete promptly. Log plugin name from error message to identify the culprit.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][4]
  • after · after-error-parameter-unchecked
    warning
    Whenthe previous register() call's plugin threw an error during initialization and after() callback ignores the err parameter
    ThrowsPlugin initialization error is silently swallowed — no exception propagates, but the plugin is not loaded
    Required handlingAlways check the err parameter in after() callback: app.after((err) => { if (err) throw err; }). Re-throwing ensures the error propagates to ready()/listen() where it can be caught.
    costmediumin prodsilent failureusers seedegraded performancevisibilitysilent
    Sources[1][10]
  • addHook · addhook-async-hook-no-try-catch
    warning
    Whenasync lifecycle hook (onRequest, preParsing, preValidation, preHandler, onSend, preSerialization) throws or rejects without try-catch
    ThrowsError triggers request error handling chain — passed to setErrorHandler if configured, otherwise returns 500 Internal Server Error
    Required handlingEITHER configure setErrorHandler at the server (Fastify routes hook throws through it, formatting the response), OR wrap async hook body in try-catch and return a meaningful response via reply.code(status).send(error). The first path is preferred for projects with cross-cutting error handling.
    costlowin proddegraded serviceusers seeservice unavailablevisibilityvisible
    Sources[11]
  • addHook · addhook-onclose-async-unhandled
    warning
    Whenasync onClose hook throws or rejects, and close() is called without try-catch (e.g., in a SIGTERM handler)
    Throwsclose() promise rejects — if not caught, becomes an unhandled rejection; database connection pool may not be released
    Required handlingAwait close() in try-catch in SIGTERM/SIGINT handlers. Wrap onClose hook body in try-catch and log errors. Use finally block to ensure cleanup code runs even if a hook fails.
    costmediumin prodsilent failureusers seedegraded performancevisibilitysilent
    Sources[7]
  • setErrorHandler · seterrorhandler-called-after-start
    error
    WhensetErrorHandler() is called after fastify.listen() or fastify.ready() has been awaited (server already started)
    ThrowsError: Cannot call "setErrorHandler" when fastify instance is already started!
    Required handlingCall setErrorHandler() during server setup, before awaiting listen() or ready(). In plugins, setErrorHandler() is always safe to call since plugins execute before server starts.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • setErrorHandler · seterrorhandler-not-function
    error
    WhensetErrorHandler() is called with a non-function argument (undefined, null, an object)
    ThrowsFST_ERR_ERROR_HANDLER_NOT_FN — TypeError: Error Handler must be a function
    Required handlingPass a function to setErrorHandler(). This is a programming error that surfaces at startup time, not in production traffic.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • setErrorHandler · seterrorhandler-already-set
    warning
    WhensetErrorHandler() is called twice in the same plugin scope without allowErrorHandlerOverride: true
    ThrowsFST_ERR_ERROR_HANDLER_ALREADY_SET — TypeError thrown synchronously
    Required handlingSet allowErrorHandlerOverride: true in fastify() options when you need to replace an existing error handler (e.g., during testing or plugin composition). Each encapsulated plugin scope can have its own error handler without this issue.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • setErrorHandler · seterrorhandler-handler-itself-throws
    warning
    Whenthe registered error handler function itself throws synchronously or its Promise rejects
    ThrowsError propagates to the parent plugin scope's error handler. If no parent handler exists, the root default handler handles it. A completely broken error handler chain causes an unformatted 500 response from the fallback handler.
    Required handlingWrap error handler body in try-catch. Log errors before sending the response. If the error handler throws, Fastify will NOT retry with the same handler — it falls back to the parent scope or root default handler, which may return a different error format than expected by clients.
    costmediumin proddegraded serviceusers seedegraded performancevisibilityvisible
    Sources[12][13]
  • addContentTypeParser · addcontenttype-body-too-large
    warning
    Whenrequest body size exceeds the bodyLimit configured in fastify options (default 1MB) or per-route bodyLimit
    ThrowsFST_ERR_CTP_BODY_TOO_LARGE — 413 Request Entity Too Large. Thrown before the custom parser is called.
    Required handlingHandle FST_ERR_CTP_BODY_TOO_LARGE in setErrorHandler to return a user-friendly 413 message. Increase bodyLimit per-route for file upload routes. Do not increase globally as it expands the attack surface for DoS.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[14][15]
  • addContentTypeParser · addcontenttype-invalid-media-type
    warning
    Whenclient sends a content-type for which no parser is registered (neither default JSON/text parser nor a custom addContentTypeParser)
    ThrowsFST_ERR_CTP_INVALID_MEDIA_TYPE — 415 Unsupported Media Type. Returned before any route handler is called.
    Required handlingRegister parsers for all content-types your API accepts. Add a catch-all parser with '*' or 'application/*' for APIs accepting arbitrary binary payloads. Handle FST_ERR_CTP_INVALID_MEDIA_TYPE in setErrorHandler to return consistent error format.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[14]
  • addContentTypeParser · addcontenttype-async-parser-rejects
    warning
    Whenan async custom parser rejects or throws (invalid encoding, decompression error, schema mismatch)
    ThrowsThe rejection error propagates to setErrorHandler with the same status code the parser set, or 500 if none was set. The raw error object is passed as-is.
    Required handlingWrap async parser body in try-catch and set err.statusCode before throwing to control the HTTP response code. Pass errors to done(err) for callback-based parsers. Without explicit status codes, parsing errors return 500 instead of the semantically correct 400.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[14]
  • setNotFoundHandler · setnotfoundhandler-called-after-start
    error
    WhensetNotFoundHandler() is called after fastify.listen() or fastify.ready() has been awaited (server already started)
    ThrowsError: Cannot call "setNotFoundHandler" when fastify instance is already started!
    Required handlingCall setNotFoundHandler() during server setup, before awaiting listen() or ready(). In plugins, setNotFoundHandler() is always safe to call since plugins execute before server starts. Late registration is a startup-only error — visible immediately on next deploy.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • setNotFoundHandler · setnotfoundhandler-already-set
    warning
    WhensetNotFoundHandler() is called twice for the same Fastify instance / plugin prefix
    ThrowsError: Not found handler already set for Fastify instance with prefix: '<prefix>' — thrown synchronously
    Required handlingRegister the 404 handler exactly once per encapsulated scope. If you need a different 404 response under a sub-prefix, register the handler inside the corresponding plugin's register() body — the plugin's scope owns its own 404 handler independently of the root.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][9]
  • setNotFoundHandler · setnotfoundhandler-handler-throws-routes-via-error-handler
    warning
    Whenthe registered 404 handler function itself throws synchronously, awaits a rejected promise, or fails to send a response
    ThrowsError is routed through setErrorHandler (NOT through the 404 path again) — the client receives the formatted error response from setErrorHandler, typically 500 Internal Server Error, NOT the intended 404. If no setErrorHandler is configured, returns an unformatted 500.
    Required handlingWrap the 404 handler body in try-catch when it does I/O (e.g., logging unknown-route attempts to a database, fetching analytics). On failure, call reply.code(404).send({ message: 'Not Found' }) explicitly so the response status reflects the real intent. Without this, debugging looks confusing — client logs show 500 from a route that should be 404.
    costmediumin proddegraded serviceusers seedegraded performancevisibilityvisible
    Sources[16][13]

Sources

Every postcondition cites at least one of these. Numbered to match the footnotes above.

  1. [1]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Server/
  2. [2]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Request/#requestsignal
  3. [3]nodejs.org/api/errors.htmlhttps://nodejs.org/api/errors.html#common-system-errors
  4. [4]github.com/fastify/avviohttps://github.com/fastify/avvio
  5. [5]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Guides/Getting-Started/
  6. [6]github.com/fastify/fastify-websockethttps://github.com/fastify/fastify-websocket
  7. [7]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Hooks/#onclose
  8. [8]github.com/fastify/avviohttps://github.com/fastify/avvio#ready
  9. [9]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Plugins/
  10. [10]github.com/fastify/avviohttps://github.com/fastify/avvio#afterfn
  11. [11]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Hooks/
  12. [12]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Server/#seterrorhandler
  13. [13]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Hooks/#onerror
  14. [14]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/ContentTypeParser/
  15. [15]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Server/#bodylimit
  16. [16]fastify.dev/docs/latesthttps://fastify.dev/docs/latest/Reference/Server/#setnotfoundhandler
Need a different package?
Request a profile