visulima error-handler
Error handlers for use in development and production environments.
Daniel Bannert's open source work is supported by the community on GitHub Sponsors
Install
npm install @visulima/error-handleryarn add @visulima/error-handlerpnpm add @visulima/error-handlerFeatures
- Content Negotiation - Automatically serves HTML, JSON, Problem JSON, or JSON:API based on
Acceptheader - Framework Agnostic - Works with Node.js HTTP, Express, Fastify, Koa, Hono, and any Fetch-based runtime
- Production Ready - Configurable error pages, trace control, and custom handlers
- TypeScript Support - Full type safety with comprehensive TypeScript definitions
- Extensible - Custom error handlers via regex matching on Accept headers
- CSP Support - Built-in Content Security Policy nonce support for inline styles
Quick Start
Node.js HTTP Server
import { createServer } from "node:http";
import httpHandler from "@visulima/error-handler/handler/http/node";
const server = createServer(async (req, res) => {
try {
// your app logic...
throw new Error("Boom!");
} catch (error) {
const handler = await httpHandler(error as Error, {
showTrace: process.env.NODE_ENV !== "production",
});
return handler(req, res);
}
});
server.listen(3000);Express Setup
import express from "express";
import httpHandler from "@visulima/error-handler/handler/http/node";
const app = express();
app.use(express.json());
app.get("/", async (req, res) => {
try {
throw new Error("Example error");
} catch (error) {
const handler = await httpHandler(error as Error, {
showTrace: process.env.NODE_ENV !== "production",
});
return handler(req, res);
}
});
app.listen(3000);Hono (Fetch Runtime)
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import fetchHandler from "@visulima/error-handler/handler/fetch";
const app = new Hono();
app.get("/", (c) => c.text("OK"));
app.get("/error", () => {
throw new Error("Boom from Hono");
});
app.onError(async (error, c) => {
const handler = await fetchHandler(error as Error, {
showTrace: process.env.NODE_ENV !== "production",
});
return handler(c.req.raw);
});
serve({ fetch: app.fetch, port: 3000 });Fetch-based Runtimes
// Cloudflare Workers
import fetchHandler from "@visulima/error-handler/handler/fetch";
export default {
async fetch(request: Request): Promise<Response> {
try {
throw new Error("Boom");
} catch (error) {
const handler = await fetchHandler(error as Error, {
showTrace: process.env.NODE_ENV !== "production",
});
return handler(request);
}
},
};// Deno
import fetchHandler from "@visulima/error-handler/handler/fetch";
Deno.serve(async (request: Request) => {
try {
throw new Error("Boom");
} catch (error) {
const handler = await fetchHandler(error as Error, {
showTrace: process.env.NODE_ENV !== "production",
});
return handler(request);
}
});Content Negotiation
The error handler automatically serves different content types based on the Accept header:
text/html→ HTML error pageapplication/problem+json→ Problem JSON (RFC 7807)application/json→ Simple JSON responseapplication/vnd.api+json→ JSON:API formattext/plain→ Plain textapplication/javascript→ JavaScript error throw
Custom Handlers
Add custom handlers for specific content types:
import httpHandler from "@visulima/error-handler/handler/http/node";
const handler = await httpHandler(error, {
extraHandlers: [
{
regex: /application\/yaml/u,
handler: (error, req, res) => {
res.setHeader("content-type", "application/yaml");
res.end(`error: ${error.message}`);
},
},
],
});API
httpHandler(error, options?) => Promise<(req, res) => Promise>
Node.js HTTP handler for Express, Connect, Fastify, Koa, and similar frameworks.
Parameters:
error: Error- The error to handleoptions?: HtmlErrorHandlerOptions & { showTrace?: boolean; extraHandlers?: ErrorHandlers }
Options:
showTrace?: boolean- Include stack trace in responses (default:true)extraHandlers?: ErrorHandlers- Custom handlers for specific Accept headerserrorPage?: string | ((params) => string | Promise<string>)- Custom HTML error pagecspNonce?: string- Content Security Policy nonce for inline stylesonError?: (error, request, response) => void | Promise<void>- Callback for custom error logging
fetchHandler(error, options?) => Promise<(request) => Promise>
Fetch API handler for Cloudflare Workers, Deno, Bun, and other Fetch-based runtimes.
Parameters:
error: Error- The error to handleoptions?: HtmlErrorHandlerOptions & { showTrace?: boolean; extraHandlers?: FetchErrorHandlers }
Options:
- Same as
httpHandlerbut usesFetchErrorHandlersfor custom handlers onError?: (error, request, response) => void | Promise<void>- Callback for custom error logging
Error Handler Types
type ErrorHandlers = {
handler: ErrorHandler;
regex: RegExp;
}[];
type FetchErrorHandlers = {
handler: FetchErrorHandler;
regex: RegExp;
}[];
type HtmlErrorHandlerOptions = {
errorPage?:
| string
| ((params: {
error: Error;
request: IncomingMessage;
response: ServerResponse;
reasonPhrase: string;
statusCode: number;
}) => string | Promise<string>);
cspNonce?: string;
onError?: (error: Error, request: IncomingMessage, response: ServerResponse) => void | Promise<void>;
};Content Negotiation Examples
Basic Usage
import { createServer } from "node:http";
import httpHandler from "@visulima/error-handler/handler/http/node";
const server = createServer(async (req, res) => {
try {
throw new Error("Test error");
} catch (error) {
const handler = await httpHandler(error as Error, {
showTrace: process.env.NODE_ENV !== "production",
});
return handler(req, res);
}
}).listen(3000);With Custom HTML Error Page
import httpHandler from "@visulima/error-handler/handler/http/node";
const handler = await httpHandler(error, {
errorPage: ({ error, statusCode }) =>
`<!DOCTYPE html>
<html>
<head><title>Error ${statusCode}</title></head>
<body>
<h1>Error ${statusCode}</h1>
<p>${error.message}</p>
</body>
</html>`,
showTrace: false,
});With CSP Nonce Support
import httpHandler from "@visulima/error-handler/handler/http/node";
const handler = await httpHandler(error, {
cspNonce: "nonce-abc123", // Will be added to <style> tags
showTrace: process.env.NODE_ENV !== "production",
});With Custom Error Logging
import httpHandler from "@visulima/error-handler/handler/http/node";
const handler = await httpHandler(error, {
onError: (error, request, response) => {
// Log to your preferred logging service
console.error(`[${new Date().toISOString()}] ${request.method} ${request.url} - ${error.message}`);
// Or send to external logging service
// logToService({ error: error.message, url: request.url, method: request.method });
},
showTrace: process.env.NODE_ENV !== "production",
});Additional Exports
This package provides additional exports for different use cases:
Runtime-Specific Handlers
For convenience, you can also import runtime-specific handlers:
// Deno
import fetchHandler from "@visulima/error-handler/handler/http/deno";
// Bun
import fetchHandler from "@visulima/error-handler/handler/http/bun";
// Cloudflare Workers
import fetchHandler from "@visulima/error-handler/handler/http/cloudflare";
// Edge Runtime
import fetchHandler from "@visulima/error-handler/handler/http/edge";
// Hono
import fetchHandler from "@visulima/error-handler/handler/http/hono";
// CLI applications
import cliHandler from "@visulima/error-handler/handler/cli";Individual Error Handlers
You can also import individual error handlers for specific content types:
import { htmlErrorHandler } from "@visulima/error-handler/error-handler/html";
import { problemErrorHandler } from "@visulima/error-handler/error-handler/problem";
import { jsonErrorHandler } from "@visulima/error-handler/error-handler/json";
import { jsonapiErrorHandler } from "@visulima/error-handler/error-handler/jsonapi";
import { textErrorHandler } from "@visulima/error-handler/error-handler/text";
import { jsonpErrorHandler } from "@visulima/error-handler/error-handler/jsonp";
import { xmlErrorHandler } from "@visulima/error-handler/error-handler/xml";Main Export
import { createNegotiatedErrorHandler } from "@visulima/error-handler";Related
- @visulima/flare - Full-featured error overlay with inspector
- @visulima/error - Error utilities and solution finders
Supported Node.js Versions
Libraries in this ecosystem make the best effort to track Node.js’ release schedule. Here’s a post on why we think this is important.
Contributing
If you would like to help take a look at the list of issues and check our Contributing guidelines.
Note: please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
Credits
License
The visulima error-handler is open-sourced software licensed under the MIT