error-message-utils helps TypeScript and JavaScript apps turn unknown errors into a
consistent shape:
- a readable message
- a stable error code
- optional extra data
Use Exception for most application code. Use encodeError and decodeError when you need to
send or receive an error code inside a plain string.
npm i -S error-message-utilsException is an Error subclass that stores a normalized message, a code, and optional data.
import { Exception } from 'error-message-utils';
throw new Exception('The provided email is already in use.', 'EMAIL_EXISTS', {
field: 'email',
});const exception = new Exception('Request failed', 'REQUEST_FAILED');
exception instanceof Error; // true
exception instanceof Exception; // true
exception.name; // 'Exception'
exception.message; // 'Request failed'
exception.code; // 'REQUEST_FAILED'
exception.data; // null
exception.toString(); // 'Request failed{(REQUEST_FAILED)}'
exception.toRecord();
// {
// message: 'Request failed',
// code: 'REQUEST_FAILED',
// data: null,
// }When you catch an unknown error, pass it to Exception. The package will extract the best message
and code it can find.
import { Exception } from 'error-message-utils';
try {
await sendReceiptEmail();
} catch (error) {
throw new Exception(error, 'RECEIPT_EMAIL_FAILED', {
operation: 'sendReceiptEmail',
});
}Create small domain-specific exception classes when your app has a stable set of error codes.
import { Exception } from 'error-message-utils';
const USER_ERROR_CODES = {
EmailTaken: 'USER_EMAIL_TAKEN',
Unauthorized: 'USER_UNAUTHORIZED',
} as const;
type IUserErrorCode = (typeof USER_ERROR_CODES)[keyof typeof USER_ERROR_CODES];
export class UserException extends Exception {
public constructor(message: string, code: IUserErrorCode, data?: unknown) {
super(message, code, data);
this.name = 'UserException';
}
}
throw new UserException(
'The provided email is already in use.',
USER_ERROR_CODES.EmailTaken,
{ field: 'email' },
);extractMessage accepts any value and returns the best readable message it can find.
import { extractMessage } from 'error-message-utils';
extractMessage(
new Error('Top level error', {
cause: new Error('First nested cause', {
cause: new Error('Second nested cause'),
}),
}),
);
// 'Top level error; [CAUSE]: First nested cause; [CAUSE]: Second nested cause'
extractMessage({
message: {
err: {
message: 'This error message is nested deeply!',
},
},
});
// 'This error message is nested deeply!'Zod errors are formatted with their first issue message and path.
import { z } from 'zod';
import { extractMessage } from 'error-message-utils';
const result = z.object({ name: z.string() }).safeParse({ name: 123 });
if (!result.success) {
extractMessage(result.error);
// 'Invalid input: expected string, received number (name)'
}extractRedactedMessage extracts a message using the same rules as extractMessage, then replaces
every exact sensitive value with [redacted].
import { extractRedactedMessage } from 'error-message-utils';
const error = new Error('Request failed for token abc123.', {
cause: new Error('The provider rejected abc123.'),
});
extractRedactedMessage(error, ['abc123']);
// 'Request failed for token [redacted].; [CAUSE]: The provider rejected [redacted].'
extractRedactedMessage(error, ['different-value']);
// 'Request failed for token abc123.; [CAUSE]: The provider rejected abc123.'Matching is literal and case-sensitive. Empty values are ignored. The function does not automatically identify secrets, so transformed or encoded versions must be supplied separately if they also need redaction.
Use getErrorCode when you only need the resolved code.
import { Exception, getErrorCode } from 'error-message-utils';
const exception = new Exception('Access denied', 'ACCESS_DENIED');
getErrorCode(exception); // 'ACCESS_DENIED'
getErrorCode('Access denied'); // nullUse hasErrorCode when you want a direct boolean check.
import { Exception, hasErrorCode } from 'error-message-utils';
const exception = new Exception('Access denied', 'ACCESS_DENIED');
hasErrorCode(exception, 'ACCESS_DENIED'); // true
hasErrorCode(exception, 'PAYMENT_FAILED'); // falseUse hasErrorCodePrefix when related string codes share a prefix. Empty prefixes and numeric codes
do not match.
import { Exception, hasErrorCodePrefix } from 'error-message-utils';
const exception = new Exception('User not found', 'USER_NOT_FOUND');
hasErrorCodePrefix(exception, 'USER_'); // true
hasErrorCodePrefix('USER_NOT_FOUND', 'USER_'); // true
hasErrorCodePrefix(exception, 'PAYMENT_'); // falseencodeError and decodeError are lower-level helpers for systems that can only pass string
messages.
import { decodeError, encodeError } from 'error-message-utils';
const encodedError = encodeError(
'The provided email is already in use.',
'EMAIL_EXISTS',
);
encodedError;
// 'The provided email is already in use.{(EMAIL_EXISTS)}'
decodeError(encodedError);
// {
// message: 'The provided email is already in use.',
// code: 'EMAIL_EXISTS',
// data: null,
// }isEncodedError returns true when an error resolves to a non-default code. For direct code
inspection, prefer getErrorCode or hasErrorCode.
import { encodeError, isEncodedError } from 'error-message-utils';
isEncodedError('Some random unencoded error'); // false
isEncodedError(new Error('Some random unencoded error')); // false
isEncodedError(encodeError('Some unknown error.', 'UNKNOWN_ERROR')); // trueUse isDefaultErrorMessage to detect the fallback message returned when no useful message can be
extracted.
import { DEFAULT_MESSAGE, isDefaultErrorMessage } from 'error-message-utils';
isDefaultErrorMessage(DEFAULT_MESSAGE); // true
isDefaultErrorMessage(`${DEFAULT_MESSAGE} More details.`); // true
isDefaultErrorMessage(`${DEFAULT_MESSAGE} More details.`, true); // falseImport public items from the package root:
import {
DEFAULT_CODE,
DEFAULT_MESSAGE,
Exception,
decodeError,
encodeError,
extractMessage,
extractRedactedMessage,
getErrorCode,
hasErrorCode,
hasErrorCodePrefix,
isDefaultErrorMessage,
isEncodedError,
type IDecodedError,
type IErrorCode,
type IErrorCodeCarrier,
type IExceptionRecord,
} from 'error-message-utils';| Export | Description |
|---|---|
Exception |
An Error subclass that normalizes an unknown error into message, code, and data. It can also serialize itself with toString() or toRecord(). |
| Export | Signature | Description |
|---|---|---|
extractMessage |
(error: unknown) => string |
Extracts the best readable message from strings, Error instances, nested error-like objects, Error.cause chains, arrays, plain objects, and Zod errors. Returns DEFAULT_MESSAGE when no useful message can be extracted. |
extractRedactedMessage |
(error: unknown, sensitiveValues: readonly string[]) => string |
Extracts a message and replaces every exact, case-sensitive occurrence of each non-empty sensitive value with [redacted]. Returns the extracted message unchanged when no value matches. |
encodeError |
(error: unknown, code: IErrorCode) => string |
Extracts a message from error and appends the wrapped code at the end of the message. |
decodeError |
(error: unknown) => IDecodedError |
Extracts a message, resolves a code from an encoded message or code-carrying object, and returns { message, code, data }. |
isEncodedError |
(error: unknown) => boolean |
Returns true when decodeError(error).code resolves to a non-default code. |
getErrorCode |
(error: unknown) => IErrorCode | null |
Returns the resolved non-default code, or null when no non-default code is found. |
hasErrorCode |
(error: unknown, code: IErrorCode) => boolean |
Checks whether an error resolves to the provided code. Raw code values are compared with strict equality. |
hasErrorCodePrefix |
(error: unknown, prefix: string) => boolean |
Checks whether an error resolves to a string code that starts with the provided non-empty prefix. Raw string codes are supported; numeric codes do not match. |
isDefaultErrorMessage |
(value: string, fullMatch?: boolean) => boolean |
Checks whether a string contains DEFAULT_MESSAGE. Pass true as the second argument to require an exact match. |
type IErrorCode = string | number;
type IDecodedError = {
message: string;
code: IErrorCode;
data: unknown | null;
};
type IErrorCodeCarrier = {
code: IErrorCode;
} & Record<string, unknown>;
type IExceptionRecord = {
message: string;
code: IErrorCode;
data: unknown | null;
};| Export | Description |
|---|---|
IErrorCode |
The supported type for application error codes. |
IDecodedError |
The object returned by decodeError. |
IErrorCodeCarrier |
A plain object shape that can provide a code to decodeError, getErrorCode, hasErrorCode, hasErrorCodePrefix, and Exception. |
IExceptionRecord |
The serializable object returned by Exception.toRecord(). |
const DEFAULT_CODE = -1;
const DEFAULT_MESSAGE =
'The error message could not be extracted, check the logs for more information.';| Export | Description |
|---|---|
DEFAULT_CODE |
The fallback code used when no code can be resolved. |
DEFAULT_MESSAGE |
The fallback message used when no readable message can be extracted. |
npm test