finalhandler: HTTP Final Responder
finalhandler is a Node.js utility function designed to standardize the final steps of an HTTP request within a server or middleware chain. It gracefully handles both successful completion (responding with a 404 for unhandled requests) and error scenarios, ensuring that the `ServerResponse` object is properly concluded and the `IncomingMessage` stream is unpiped. Currently at version 2.1.1, the library maintains an active development and maintenance cadence, with recent updates in both its v1 and v2 major versions. Its primary differentiation lies in providing a low-level, unopinionated mechanism for robust error and 404 response handling, including options for custom error logging, making it a foundational component for web frameworks like Express and Connect.
Common errors
-
ReferenceError: require is not defined
cause Attempting to use CommonJS `require()` syntax directly in a Node.js ES Module file without a compatibility shim.fixIn ES Modules, use `import finalhandler from 'finalhandler'` for loading. If you require `require()` functionality within an ESM file for other CJS modules, you can use `import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);`. -
Error: Can't set headers after they are sent to the client
cause This error occurs when an attempt is made to modify HTTP headers or the status code after the server has already sent the response headers or the full response body to the client. This typically happens if multiple error handlers or middleware incorrectly try to respond to the same request.fixReview your middleware chain and error handling logic. Ensure that `finalhandler` is called exclusively when no other response has been sent, or that preceding middleware correctly passes errors down the chain without prematurely sending a response. Check `res.headersSent` before attempting to modify headers. -
Error response does not contain a stack trace in production
cause `NODE_ENV` environment variable is set to 'production', or the `env` option passed to `finalhandler` is explicitly 'production'. In production environments, `finalhandler` intentionally omits stack traces from HTTP responses for security.fixThis is expected behavior in production. For debugging, ensure `NODE_ENV=development` or `options.env` is not 'production'. For production error visibility, implement custom error logging using the `onerror` option to send stack traces to an internal logging service instead of exposing them to clients.
Warnings
- breaking Version 2.0.0 of `finalhandler` dropped support for Node.js versions older than 18.0.0. Projects running on Node.js <18 will need to upgrade their Node.js environment or remain on `finalhandler` v1.x.
- breaking Version 1.2.0 introduced a change by removing 'set content headers that break response'. This was an internal adjustment to avoid issues but could subtly affect applications that relied on specific default headers being set by `finalhandler` in earlier versions.
- gotcha By default, when `NODE_ENV` is set to 'production' (or `options.env` is 'production'), `finalhandler` will suppress the stack trace in the HTTP error response body for security reasons. Instead, it will send a generic status message.
- gotcha If `finalhandler` is invoked after `res.headersSent` is `true` (meaning headers have already been sent to the client), it will not attempt to set new headers or status codes. While it will still try to end the response, any attempts to modify the status code or add headers for the error will be ignored, potentially leading to incorrect client-side error handling if the initial headers were misleading.
Install
-
npm install finalhandler -
yarn add finalhandler -
pnpm add finalhandler
Imports
- finalhandler
const finalhandler = require('finalhandler') - finalhandler
import { finalhandler } from 'finalhandler'import finalhandler from 'finalhandler'
- finalhandler
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); const finalhandler = require('finalhandler');
Quickstart
const finalhandler = require('finalhandler');
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
const done = finalhandler(req, res, { onerror: logerror });
fs.readFile('index.html', (err, buf) => {
if (err) return done(err);
res.setHeader('Content-Type', 'text/html');
res.end(buf);
});
});
server.listen(3000, () => {
console.log('Server listening on port 3000');
});
function logerror (err) {
console.error('Error encountered:', err.stack || err.toString());
}
// To make this runnable, create a dummy index.html
// For example, echo '<h1>Hello World!</h1>' > index.html