Configuration
1. Overview
The configuration system is accessed via setConfig(options).
All configuration must be provided before the error handler middleware is initialized.
2. Default Configuration Interface
The setConfig function accepts a single object parameter with optional properties. The configuration is stored in a module-level singleton and affects all subsequent error handling operations.
Default configuration settings:
When setConfig is not called, the library uses the following default configuration defined in
setConfig({
customMappers: [],
customLogger: null,
errorClasses: null,
needMappers: null,
maxLoggerRequests: 100,
devEnvironments: ['dev', 'development'],
formatError: (err, {req, isDev}) => ({
status: err.isOperational ? 'fail' : 'error',
message: err.message,
...(isDev ? {
method: req.method,
url: req.originalUrl,
stack: err.stack
} : {})
})
})3. Configuration Options Reference
customMappers
Type: ErrorMapper[]
Default: []
Validation: Must be an array of synchronous functions (no async functions or Promises)
An ordered array of custom error mapping functions executed before built-in mappers. Each mapper receives an error and request object, returning either a transformed AppError or undefined/null to pass to the next mapper.
Interface:
interface ErrorMapper {
(err: AppError | Error, req: Request): AppError | Error | undefined | null;
}Execution Order:
- Custom mappers (array order)
- Library-specific mappers (filtered by
needMappers) - Name-based mapper (native errors)
- Fallback (500 Internal Server Error)
Example:
setConfig({
customMappers: [
(err) => {
if (err.name === 'PaymentGatewayError') {
return Errors.PaymentRequired('Payment processing failed');
}
},
(err) => {
if (err.code === 'ECONNREFUSED') {
return Errors.ServiceUnavailable('External service unavailable');
}
}
]
});errorClasses
Type: ErrorClasses | null
Default: null
Validation: Must be an object
Provides error constructor references for strict instanceof checks instead of duck-typing.
Currently (v1.8.1+) supports Zod and Joi validation libraries.
Interface:
interface ErrorClasses {
Zod?: { ZodError: new (...args: any[]) => Error }
Joi?: { ValidationError: new (...args: any[]) => Error }
}Without errorClasses, the library uses duck-typing to detect error types (checking for properties like error.issues for Zod).
With errorClasses, the library performs strict instanceof checks for more reliable type detection.
Example:
import { zod } from 'zod'
import Joi from 'joi'
setConfig({
errorClasses: {
Zod: z,
Joi: Joi
}
});needMappers
Type: string[] | null
Default: null (all mappers enabled)
Validation: Must be an array
Enables selective activation of library-specific error mappers, reducing overhead when certain libraries are not used in the application.
Valid Mapper Names:
'zod'- Zod validation errors'joi'- Joi validation errors'expressValidator'- express-validator errors'mongoose'- Mongoose/MongoDB errors'prisma'- Zod validation errors'sequelize'- Sequelize ORM errors
When needMappers is null, all mappers are active. When specified, only listed mappers execute. Custom mappers and name-based mappers always execute regardless of this setting.
Example:
setConfig({
needMappers: ['zod', 'prisma'] // Only map Zod and Prisma errors
});customLogger
Type: Logger | null
Default: null
Validation: Must be an object with methods error, warn, info, debug
Replaces the built-in console logger with a custom logging implementation. When provided, all logging calls are delegated to this logger instead of the internal logger.
Interface:
export interface Logger {
error(message: any, ...args: any[]): void
warn(message: any, ...args: any[]): void
info(message: any, ...args: any[]): void
debug(message: any, ...args: any[]): void
} Example:
import winston from 'winston'
const levels = {
error: 0,
warn: 1,
info: 2,
debug: 3,
};
const logger = winston.createLogger({
level: levels,
format: winston.format.json(),
transports: [new winston.transports.File({ filename: 'error.log' })]
});
setConfig({ customLogger: logger });maxLoggerRequests
Type: number
Default: 100
Validation: Must be a number
Sets the maximum number of log entries allowed per minute. This rate limiting prevents log flooding in high-error scenarios, protecting log storage and performance.
When the limit is exceeded, additional log requests are silently dropped until the next minute window.
Example:
setConfig({
maxLoggerRequests: 1000 // Allow 1000 logs per minute
});devEnvironments
Type: string[]
Default: ['dev', 'development']
Validation: Must be a array
Defines which NODE_ENV values are considered development environments. This controls error verbosity and stack trace inclusion in responses.
Checks if process.env.NODE_ENV matches any value in this array. When true:
- Full stack traces included in responses
- Request method and URL exposed
- Detailed validation error messages
- Database field names revealed
Example:
setConfig({
devEnvironments: ['development', 'dev', 'staging', 'local']
});formatError
Type: (err: AppError | Error, options: ConfigOptions) => any
Default: See below
Validation: Must be a function
Custom formatter for the final error response sent to clients. This enables adherence to API standards like JSON:API or legacy response formats.
Interface:
interface ConfigOptions {
req: Request
isDev: boolean
}
type FormatError = (err: AppError | Error, options: ConfigOptions) => anyDefault Implementation:
formatError: (err, {req, isDev}) => ({
status: err.isOperational ? 'fail' : 'error',
message: err.message,
...(isDev ? {
method: req.method,
url: req.originalUrl,
stack: err.stack
} : {})
})The formatter receives the error object (which is always an AppError instance after mapping) and a context object containing the Express request and environment flag.
Example (JSON:API format):
setConfig({
formatError: (err, {req, isDev}) => ({
errors: [{
status: err.statusCode.toString(),
title: err.message,
detail: isDev ? err.stack : undefined,
source: isDev ? {
pointer: req.originalUrl
} : undefined
}]
})
});4. Configuration Timing
Configuration must be set before the error handler middleware is registered:
import express from 'express'
import { setConfig, errorHandler } from 'ds-express-errors'
const app = express();
// 1. Set configuration FIRST
setConfig({
customLogger: winston.createLogger({...}),
devEnvironments: ['development', 'staging'],
maxLoggerRequests: 500
});
// 2. Register routes
app.get('/api/users', ...);
// 3. Register error handler LAST
app.use(errorHandler);
app.listen(3000);
Once errorHandler is invoked, it reads from the configuration singleton. Calling setConfig after error handler registration affects subsequent errors but not errors already in flight.
