Comprehensive error handling middleware for Koa.js applications that overrides ctx.onerror with flexible response formatting
npx @tessl/cli install tessl/npm-koa-onerror@5.0.0Koa Onerror is an error handling middleware for Koa.js applications that overrides the default ctx.onerror method to provide comprehensive error handling. It offers flexible error response formatting with automatic content negotiation, supports both development and production modes, and handles stream errors that can't be caught by traditional try-catch blocks.
npm install koa-onerrorimport { onerror } from "koa-onerror";
// Also available: OnerrorError, OnerrorHandler, OnerrorOptions typesFor CommonJS:
const { onerror } = require("koa-onerror");import Koa from "koa";
import { onerror } from "koa-onerror";
const app = new Koa();
// Apply error handling middleware
onerror(app);
// Your other middleware
app.use(async (ctx) => {
// This error will be handled by koa-onerror
throw new Error("Something went wrong!");
});
app.listen(3000);Koa Onerror works by replacing the default ctx.onerror method with a more sophisticated error handler that:
stream-wormholeMain function that configures comprehensive error handling for a Koa application.
/**
* Configure error handling middleware for a Koa application
* @param app - Koa application instance
* @param options - Optional configuration for error handlers
* @returns The modified Koa application instance
*/
function onerror(app: any, options?: OnerrorOptions): any;Usage Example:
import Koa from "koa";
import { onerror } from "koa-onerror";
const app = new Koa();
// Basic usage with default handlers
onerror(app);
// With custom options
onerror(app, {
// Custom JSON error handler
json(err, ctx) {
ctx.body = {
success: false,
error: err.message,
code: err.status || 500
};
},
// Redirect for HTML/text errors
redirect: "/error-page",
// Universal error handler (overrides content negotiation)
all(err, ctx) {
console.error("Error occurred:", err);
ctx.body = "An error occurred";
}
});Enhanced error object interface used throughout the error handling system.
/**
* Extended Error object with additional properties for HTTP error handling
*/
type OnerrorError = Error & {
/** HTTP status code for the error response */
status: number;
/** Optional HTTP headers to include in the error response */
headers?: Record<string, string>;
/** Whether to expose detailed error information to clients */
expose?: boolean;
};Function signature for custom error handling callbacks.
/**
* Custom error handler function signature
* @param err - The error object with additional HTTP properties
* @param ctx - Koa context object
*/
type OnerrorHandler = (err: OnerrorError, ctx: any) => void;Comprehensive configuration interface for customizing error handling behavior.
/**
* Configuration options for koa-onerror middleware
*/
type OnerrorOptions = {
/** Custom handler for text/plain responses */
text?: OnerrorHandler;
/** Custom handler for application/json responses */
json?: OnerrorHandler;
/** Custom handler for text/html responses */
html?: OnerrorHandler;
/** Universal handler that bypasses content negotiation */
all?: OnerrorHandler;
/** Custom handler for application/javascript responses (JSONP) */
js?: OnerrorHandler;
/** Redirect URL for HTML/text errors instead of showing error page */
redirect?: string | null;
/** Custom content negotiation function */
accepts?: (...args: string[]) => string;
};Detailed Option Usage:
onerror(app, {
// Override default text handler
text(err, ctx) {
ctx.body = `Error ${err.status}: ${err.message}`;
},
// Override default JSON handler
json(err, ctx) {
ctx.body = {
error: {
message: err.message,
status: err.status,
timestamp: new Date().toISOString()
}
};
},
// Override default HTML handler
html(err, ctx) {
ctx.body = `
<h1>Error ${err.status}</h1>
<p>${err.message}</p>
<p>Please try again later.</p>
`;
},
// Handle JSONP responses
js(err, ctx) {
const callback = ctx.query.callback || 'callback';
ctx.body = `${callback}(${JSON.stringify({ error: err.message })})`;
},
// Redirect instead of showing error
redirect: '/error-page',
// Universal handler (overrides content negotiation)
all(err, ctx) {
// Log error internally
console.error('Application Error:', err);
// Send simple response regardless of Accept header
ctx.status = err.status || 500;
ctx.body = 'An unexpected error occurred';
},
// Custom content negotiation
accepts(...types) {
// Custom logic to determine response type
return this.get('User-Agent').includes('mobile') ? 'json' : 'html';
}
});stream-wormhole to properly dispose of request streams during errorsThe middleware automatically determines the response format based on the client's Accept header:
text/html → HTML error page (using built-in templates)application/json → JSON error responsetext/plain → Plain text error messageapplication/javascript → Custom JavaScript/JSONP handling (if js handler provided)Error exposure is controlled by the NODE_ENV environment variable:
The package includes two HTML error templates:
When errors occur, the middleware enhances them with additional properties:
// Original error
const err = new Error("Database connection failed");
// Enhanced by koa-onerror
err.status = 500;
err.headers = { 'X-Error-Code': 'DB_CONN_FAIL' };
err.expose = false; // Don't expose in production
// The enhanced error is then processed by the appropriate handlerThe middleware integrates seamlessly with Koa's error handling system:
ctx.onerror method on all contextsonerror(app, {
json(err, ctx) {
ctx.body = {
success: false,
error: {
code: err.code || 'UNKNOWN_ERROR',
message: err.message,
status: err.status || 500
},
requestId: ctx.state.requestId
};
}
});onerror(app, {
html(err, ctx) {
const errorPage = getErrorTemplate(err.status);
ctx.body = errorPage.replace('{{message}}', err.message);
},
redirect: null // Don't redirect, use custom template
});onerror(app, {
all(err, ctx) {
// Log error with context
logger.error('Request error', {
error: err.message,
stack: err.stack,
url: ctx.url,
method: ctx.method,
userAgent: ctx.get('User-Agent'),
ip: ctx.ip
});
// Then handle normally based on content type
const type = ctx.accepts('html', 'json', 'text');
if (type === 'json') {
ctx.body = { error: 'Internal server error' };
} else {
ctx.body = 'An error occurred';
}
}
});