Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
merge-error-cause
Advanced tools
Merge an error with its cause
.
This merges
error.cause
recursively with its parent error
, including its
message
,
stack
,
name
and
errors
.
Please reach out if you're looking for a Node.js API or CLI engineer (11 years of experience). Most recently I have been Netlify Build's and Netlify Plugins' technical lead for 2.5 years. I am available for full-time remote positions.
import mergeErrorCause from 'merge-error-cause'
const main = (userId) => {
try {
return createUser(userId)
} catch (error) {
throw mergeErrorCause(error)
// Printed as:
// TypeError: Invalid user id: false
// Could not create user.
}
}
const createUser = (userId) => {
try {
validateUserId(userId)
return sendDatabaseRequest('create', userId)
} catch (cause) {
throw new Error('Could not create user.', { cause })
}
}
const validateUserId = (userId) => {
if (typeof userId !== 'string') {
throw new TypeError(`Invalid user id: ${userId}.`)
}
}
main(false)
npm install merge-error-cause
This package works in both Node.js >=18.18.0 and browsers.
This is an ES module. It must be loaded using
an import
or import()
statement,
not require()
. If TypeScript is used, it must be configured to
output ES modules,
not CommonJS.
error
Error | any
Return value: Error
error
is modified and returned.
If error
's class is Error
or if error.wrap
is true
,
error.cause
is modified and returned instead.
If error
is not a valid Error
, a new error
is created and returned
instead.
This never throws.
error.cause
is a
recent
JavaScript feature to wrap error messages and properties.
try {
validateUserId(userId)
sendDatabaseRequest('create', userId)
} catch (cause) {
throw new Error('Could not create user.', { cause })
}
However, it comes with a few issues.
error.cause
Consumers need to traverse error.cause
.
try {
createUser(userId)
} catch (error) {
if (error.code === 'E101' || (error.cause && error.cause.code === 'E101')) {
// Checking for properties requires traversing `error.cause`
}
if (
error.name === 'UserError' ||
(error.cause && error.cause.name === 'UserError')
) {
// So does checking for error class
}
}
This is tricky to get right. For example:
error.cause.cause
might also exist (and so on)error
is not an Error
instance, error.name
might throwerror.cause
might be an infinite cycleThis library merges error.cause
recursively. It also
ensures error
is an Error
instance. Consumers can then
handle errors without checking its cause
.
try {
createUser(userId)
} catch (error) {
if (error.code === 'E101') {
/* ... */
}
if (error.name === 'UserError') {
/* ... */
}
}
Stack traces with multiple error.cause
can be quite verbose.
Error: Could not create user group.
at createUserGroup (/home/user/app/user_group.js:19:9)
at createGroups (/home/user/app/user_group.js:101:10)
at startApp (/home/user/app/app.js:35:20)
at main (/home/user/app/app.js:3:4) {
[cause]: Error: Could not create user.
at newUser (/home/user/app/user.js:52:7)
at createUser (/home/user/app/user.js:43:5)
at createUserGroup (/home/user/app/user_group.js:17:11)
at createGroups (/home/user/app/user_group.js:101:10)
at startApp (/home/user/app/app.js:35:20)
at main (/home/user/app/app.js:3:4) {
[cause]: Error: Invalid user.
at validateUser (/home/user/app/user.js:159:8)
at userInstance (/home/user/app/user.js:20:4)
at newUser (/home/user/app/user.js:50:7)
at createUser (/home/user/app/user.js:43:5)
at createUserGroup (/home/user/app/user_group.js:17:11)
at createGroups (/home/user/app/user_group.js:101:10)
at startApp (/home/user/app/app.js:35:20)
at main (/home/user/app/app.js:3:4) {
[cause]: UserError: User "15" does not exist.
at checkUserId (/home/user/app/user.js:195:3)
at checkUserExist (/home/user/app/user.js:170:10)
at validateUser (/home/user/app/user.js:157:23)
at userInstance (/home/user/app/user.js:20:4)
at newUser (/home/user/app/user.js:50:7)
at createUser (/home/user/app/user.js:43:5)
at createUserGroup (/home/user/app/user_group.js:17:11)
at createGroups (/home/user/app/user_group.js:101:10)
at startApp (/home/user/app/app.js:35:20)
at main (/home/user/app/app.js:3:4)
}
}
}
Each error cause is indented and printed separately.
This library only keeps the innermost stack trace. Error messages are concatenated by default from innermost to outermost. This results in much simpler stack traces without losing any information.
TypeError: User "15" does not exist.
Invalid user.
Could not create user.
Could not create user group.
at checkUserId (/home/user/app/user.js:195:3)
at checkUserExist (/home/user/app/user.js:170:10)
at validateUser (/home/user/app/user.js:157:23)
at userInstance (/home/user/app/user.js:20:4)
at newUser (/home/user/app/user.js:50:7)
at createUser (/home/user/app/user.js:43:5)
at createUserGroup (/home/user/app/user_group.js:17:11)
at createGroups (/home/user/app/user_group.js:101:10)
at startApp (/home/user/app/app.js:35:20)
at main (/home/user/app/app.js:3:4)
Only the innermost stack trace is kept.
Please make sure you use async
/await
instead of new Promise()
or callbacks
to prevent truncated stack traces.
Inner error messages are printed first.
try {
throw new Error('Invalid user id.')
} catch (cause) {
throw new Error('Could not create user.', { cause })
// Printed as:
// Error: Invalid user id.
// Could not create user.
}
If the outer error message ends with :
, it is prepended instead.
try {
throw new Error('Invalid user id.')
} catch (cause) {
throw new Error('Could not create user:', { cause })
// Printed as:
// Error: Could not create user: Invalid user id.
}
:
can optionally be followed by a newline.
try {
throw new Error('Invalid user id.')
} catch (cause) {
throw new Error('Could not create user:\n', { cause })
// Printed as:
// Error: Could not create user:
// Invalid user id.
}
The outer error class is used.
try {
throw new TypeError('User id is not a string.')
} catch (cause) {
const error = new UserError('Could not create user.', { cause })
const mergedError = mergeErrorCause(error)
console.log(mergedError instanceof UserError) // true
console.log(mergedError.name) // 'UserError'
}
If the parent error class is Error
, the child class is used instead. This
allows wrapping the error message or properties while keeping its class.
try {
throw new TypeError('User id is not a string.')
} catch (cause) {
const error = new Error('Could not create user.', { cause })
console.log(mergeErrorCause(error) instanceof TypeError) // true
}
error.wrap: true
has the same effect, but works with any parent error class.
try {
throw new TypeError('User id is not a string.')
} catch (cause) {
const error = new UserError('Could not create user.', { cause })
error.wrap = true
console.log(mergeErrorCause(error) instanceof TypeError) // true
}
Error properties are shallowly merged.
// Both `userId` and `invalidUser` are kept
try {
throw Object.assign(new Error('Invalid user id.'), { userId: '5' })
} catch (cause) {
throw Object.assign(new Error('Could not create user.', { cause }), {
invalidUser: true,
})
}
Empty error messages are ignored. This is useful when wrapping error properties.
try {
throw new Error('Invalid user id.')
} catch (cause) {
throw Object.assign(new Error('', { cause }), { invalidUser: true })
}
Any
aggregateError.errors[*].cause
is processed recursively. However, aggregateError.errors
are not merged with
each other since those are different from each other.
If both error.errors
and error.cause.errors
exist, they are concatenated.
Invalid errors are normalized
to proper Error
instances.
try {
throw 'Invalid user id.'
} catch (error) {
console.log(mergeErrorCause(error)) // Error: Invalid user id.
}
modern-errors
: Handle errors in
a simple, stable, consistent wayerror-custom-class
: Create
one error classerror-class-utils
: Utilities
to properly create error classeserror-serializer
: Convert
errors to/from plain objectsnormalize-exception
:
Normalize exceptions/errorsis-error-instance
: Check if
a value is an Error
instanceset-error-class
: Properly
update an error's classset-error-message
: Properly
update an error's messagewrap-error-message
:
Properly wrap an error's messageset-error-props
: Properly
update an error's propertiesset-error-stack
: Properly
update an error's stackerror-cause-polyfill
:
Polyfill error.cause
handle-cli-error
: 💣 Error
handler for CLI applications 💥log-process-errors
: Show
some ❤ to Node.js process errorserror-http-response
:
Create HTTP error responseswinston-error-format
: Log
errors with WinstonFor any question, don't hesitate to submit an issue on GitHub.
Everyone is welcome regardless of personal background. We enforce a Code of conduct in order to promote a positive and inclusive environment.
This project was made with ❤️. The simplest way to give back is by starring and sharing it online.
If the documentation is unclear or has a typo, please click on the page's Edit
button (pencil icon) and suggest a correction.
If you would like to help us fix a bug or add a new feature, please check our guidelines. Pull requests are welcome!
FAQs
Merge an error with its inner cause
We found that merge-error-cause demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.