Error chaining with the cause option
Wrapping low-level errors
When a low-level error happens deep in the stack, you usually want to add context before re-throwing β but you don't want to lose the original error. The { cause } option on Error does both:
async function loadProfile(userId) {
try {
return await db.findUser(userId);
} catch (err) {
throw new Error(\`failed to load profile for ${userId}\`, { cause: err });
}
}The caller catches the high-level error AND can drill into err.cause to inspect the original.
try {
await loadProfile("u_123");
} catch (err) {
console.error(err.message); // "failed to load profile for u_123"
console.error(err.cause?.message); // the underlying db error
}Why not just re-throw?
Re-throwing keeps the message but loses the "where in the high-level flow did this happen" context. Wrapping adds business semantics; cause preserves the technical detail. Both layers stay available.
Stack vs cause
.stack shows where it was thrown. .cause shows what triggered it. Together they're invaluable in production logs.
Sign up to start coding
Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial β card required, cancel anytime.
Sign up β free trial βFirst 10 lessons in each track are free. No card needed for those.