Global Error Handling
Catch unhandled exceptions and route misses centrally using .onError() and .notFound(). Standardize error envelopes across your entire API.
Taser.js features a centralized error handling architecture configured on the createTaserApp() builder in src/taser.ts.
Centralized onError Boundary
Any uncaught exception thrown during middleware execution, input validation, or route handlers is passed directly to .onError():
import { createTaserApp, ValidationError, type InferAppContext } from "@taserjs/router";
import { internalServerError, notFound, unprocessableEntity } from "@taserjs/router/reply";
import { context } from "./context.js";
export class ResourceNotFoundError extends Error {
constructor(public resource: string) {
super(`${resource} not found`);
this.name = "ResourceNotFoundError";
}
}
export default createTaserApp()
.context(context)
.onError((error, ctx) => {
// 1. Handle Schema Validation Errors
if (error instanceof ValidationError) {
return unprocessableEntity({
status: 422,
error: "Unprocessable Entity",
issues: error.issues,
});
}
// 2. Handle Custom Domain Exceptions
if (error instanceof ResourceNotFoundError) {
return notFound({
status: 404,
error: "Not Found",
message: error.message,
});
}
// 3. Handle Unexpected Server Exceptions
console.error(`[Error on ${ctx?.method} ${ctx?.path}]:`, error);
const isProduction = process.env.NODE_ENV === "production";
return internalServerError({
status: 500,
error: "Internal Server Error",
message: isProduction ? "An unexpected error occurred" : (error as Error).message,
});
});Customizing 404 Not Found Handling
Use .notFound() to define a standardized response when an incoming request does not match any registered route:
import { notFound } from "@taserjs/router/reply";
export default createTaserApp()
.context(context)
.notFound((ctx) => {
return notFound({
status: 404,
error: "Not Found",
message: `The endpoint ${ctx.method} ${ctx.path} does not exist on this server.`,
});
});Throwing Errors in Route Handlers
Because .onError() catches all unhandled exceptions, you can throw errors directly inside services or handlers without manual try/catch boilerplate:
import { json } from "@taserjs/router/reply";
import { t } from "@taserjs/router";
import { ResourceNotFoundError } from "../../errors.js";
export default t.get("/teams/:id").handler(async (ctx) => {
const team = await ctx.db.findTeam(ctx.params.id);
if (!team) {
// Automatically caught by .onError() and mapped to 404 JSON response:
throw new ResourceNotFoundError("Team");
}
return json(team);
});Related Guides
Streaming and Files
Stream binary data, pipe readable streams, return Blob/Buffer payloads, and serve local files with path traversal security.
CORS Middleware
Configure Cross-Origin Resource Sharing (CORS) using @taserjs/router/cors with static origins, dynamic domain resolvers, and preflight support.