
Research
/Security News
Fake imToken Chrome Extension Steals Seed Phrases via Phishing Redirects
Mixed-script homoglyphs and a lookalike domain mimic imToken’s import flow to capture mnemonics and private keys.
@vltpkg/error-cause
Advanced tools
Utility functions for Error creation to help enforce vlt's Error.cause conventions.
Usage · Error Reporting · Conventions · Error Types
Most node programs have a mishmash of error codes and various
Error subtypes, all in different shapes, making error handling
and reporting more difficult at the top level. This negatively
impacts debugging and user experience.
The JavaScript Error constructor has a cause
option
which is supported since Node 16.9. We should use it!
This module makes that easy.
import { error, typeError } from '@vltpkg/error-cause'
// create an error when a lower-level thing fails
try {
doSomethign()
} catch (er) {
throw error('The something for the whatever failed', er)
}
// create an error with some extra information
if (!thing.valid) {
throw error('the thing is not valid', {
code: 'EINVAL',
found: thing,
})
}
// create an error from a lower-level error with extra info
try {
doSomethign(thing)
} catch (er) {
throw error('the thing is not valid', {
code: 'EINVAL',
found: thing,
cause: er,
})
}
// create an error and prune some stack frames
// use this when we want to report the location of a
// function call, not its internals.
const checkBar = () => {
if (!bar) {
// will report from the checkBar() call, not here.
throw error('no bar', { found: bar, wanted: true }, checkBar)
}
// ...
}
The functions will create an error object with a cause property
if set, and the type checks will ensure that the cause object
matches vlt's conventions.
console.error(er) should not fill the entire scrollback
buffer.cause property.The following conventions should be followed for all Error
creation and handling throughout the vlt codebase.
cause. Use a
previously-thrown error as the cause option.cause. If more info can
be added to a prior throw, nest the cause properties like
{ some, other, info, cause: priorError }.cause, even if no prior error. Use a plain-old
JavaScript object following our field conventions.Error. Just create a plain old Error, and
set the cause with additional information.Whenever possible, if no remediation or extra information can usefully be added, it's best to just not handle errors and let them be raised at the higher level. For example, instead of this:
let data
try {
data = await readFile(someFile)
} catch (er) {
throw new Error('could not read some file!')
}
this is preferred:
const data = await readFile(someFile)
cause.If we can add information or do something else useful for the
user in understanding the problem, do so by creating a new
Error and setting the original thrown error as the cause.
let data
try {
data = await readFile(someFile, 'utf8')
} catch (er) {
// adds semantic information about what the file was for
throw error('The lock file was not found', er)
}
cause.If we can add even more information, that should ideally not be
put on the Error we throw, but on a cause object. Because
cause objects can nest, we can do something like this:
let data
try {
data = await readFile(someFile, 'utf8')
} catch (er) {
throw error(`could not resolve '${name}'`, {
// extra data about the situation
// it's ok to put big noisy objects in here, not on the error
// object itself!
name,
spec,
target,
// original error that was thrown
cause: er,
})
}
cause, even if no prior error.Instead of this:
throw Object.assign(new Error('could not resolve'), {
code: 'ERESOLVE',
from,
spec,
registry,
})
Do this instead:
throw error('could not resolve', {
code: 'ERESOLVE',
from,
spec,
registry,
})
This makes any big objects easily skipped if we want to just
output the error with console.error() or something, but still
preserves any debugging information that might be useful all the
way down the chain.
In some rare low-level cases, there are operations we perform that are very similar to a node filesystem operation.
For example, the @vltpkg/which module raises an error that is
intentionally similar to node's filesystem ENOENT errors,
because that is semantically sensible.
In those cases, the error must follow node's conventions as
close as possible. If we feel the need to add additional
information beyond a known system error code, string path, etc.,
or if the message isn't one that is typically raised by the
underlying system, then it's a good sign that we ought to be
creating an Error with a cause so that it can be reported
more usefully.
In such cases, this is fine:
// identical to the error thrown by node's fs
throw Object.assign(new Error('not found'), {
path: someFile,
code: 'ENOENT',
})
But this is way out of bounds and makes no sense:
throw Object.assign(new Error('could not resolve'), {
code: 'EPERM',
spec,
config: someHugeConfigObjectOrSomething,
})
Do not copy properties from a lower-level error or cause onto
the new cause object. That is unnecessary, and obscures the
origin of problems. Instead, just include the lower-level error
as the cause property. If you already have a low-level error,
you don't need to invent a synthetic one!
For example, do not do this:
let data
try {
data = await readFile(lockFile, 'utf8')
} catch (er) {
throw error('lockfile not found', {
code: er.code,
path: er.path,
})
}
Instead, do this:
let data
try {
data = await readFile(lockFile, 'utf8')
} catch (er) {
throw new Error('lockfile not found', { cause: er })
}
Error.Just use the Error classes defined in the language. Additional
information about error causes should be on the cause property,
not implicit in the constructor type.
I.e. do not do this:
class VersionError extends Error {
version?: Version
constructor(version: Version | string) {
super('Could not version')
this.version = Version.parse(version)
}
}
// ...
throw new VersionError(myVersion)
Instead, do this:
throw error('Could not version', { version })
cause Field ConventionsAll of these are optional. Additional fields may be used where appropriate, and should be added to this list over time.
cause - The cause field within a cause object should
always be an Error object that was previously thrown. Note
that the cause on an Error itself might also be a
previously thrown error, if no additional information could be
usefully added beyond improving the message.name - String. The name of something.offset - Number. The offset in a Buffer or file where we are
trying to read or write.registry - String or URL. A package registry.code - This must be a string if set, and should
only be present if it's one of our creation, not a code raised
on a system error. Eg, ERESOLVE, not ENOENT.path - The target of a file system operation.target - path on disk that is being written or extracted tospec - a @vltpkg/spec.Spec object relevant to the operation
that failed.from - string. The file path origin of a resolution that
failed, for example in the case of relative file: specifiers.status - Number or null. Either the exit code of a process or
an HTTP response status code.signal - NodeJS.Signals string or null, indicating the
signal that terminated a process.validOptions - Array of valid options when something is not a
valid option. (For use in did you mean X? output.)todo - String message indicating what bit of work this might
be a part of, what feature needs to be implemented, etc. Eg, { todo: 'nested workspace support' }.wanted - A desired value that was not found, or a regular
expression or other pattern describing it.found - The actual value, which was not wanted.max - A maximum value, which was exceeded.min - A minimum value, which was not met.response - An HTTP response or
@vltpkg/registry-client.CacheEntryurl - A string or URL objectrepository - String git repository remoteversion - string or @vltpkg/semver.Versionrange - string or @vltpkg/semver.Rangemanifest - @vltpkg/pick-manifest.Manifestpackument - @vltpkg/pick-manifest.Packumentcwd - The current working directory of a process that failedstring was expected and a number was provided, throw a
TypeError. Do not use it for a value that is the correct
type but otherwise invalid, such as a string argument that is
actually a string but does not match an expected pattern.SyntaxError.Error.FAQs
vlts Error.cause convention
The npm package @vltpkg/error-cause receives a total of 45,873 weekly downloads. As such, @vltpkg/error-cause popularity was classified as popular.
We found that @vltpkg/error-cause demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 6 open source maintainers 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.

Research
/Security News
Mixed-script homoglyphs and a lookalike domain mimic imToken’s import flow to capture mnemonics and private keys.

Security News
Latio’s 2026 report recognizes Socket as a Supply Chain Innovator and highlights our work in 0-day malware detection, SCA, and auto-patching.

Company News
Join Socket for live demos, rooftop happy hours, and one-on-one meetings during BSidesSF and RSA 2026 in San Francisco.