ES6+intermediate
Optional Catch Binding and Error Cause
Two smaller but useful ES additions: catching an error without naming a variable, and chaining errors together with a structured cause property.
Two small additions that remove noise and preserve information.
Optional catch binding is like setting aside an incident report once you've decided the incident doesn't change your response. Error cause is a doctor's referral note stating the original diagnosis, rather than a new specialist writing a fresh assessment with no trace back to what started it all.
Key Concepts
1
Optional catch binding: omit the parameter when you do not use it.
try {
return JSON.parse(text);
} catch {
return null;
}2
Before ES2019 the binding was required, so every ignored error had an unused (e) — which linters then
flagged.
(e)
3
Error cause chains errors together.
try {
await db.query(sql);
} catch (err) {
throw new Error('Failed to load user profile', { cause: err });
}4
The original is preserved on .cause rather than being replaced.
.cause
5
Which fixes the thing that makes production debugging hard. Without it, wrapping an error means choosing:
6
throw new Error('Failed to load profile'); // loses the real cause
throw err; // loses the context7
Both lose something. With cause you keep the high-level description and the underlying failure.
cause
8
let e = err;
while (e) { log(e.message); e = e.cause; }9
// Failed to load user profile
// -> Query timed out
// -> ECONNREFUSED 10.0.0.5:543210
Three layers, each adding context, ending at the actual problem. Node's console.error prints the chain.
console.error
11
Custom error classes take it too.
class AppError extends Error {
constructor(msg, options) {
super(msg, options); // pass options through for cause
this.name = 'AppError';
}
}12
Forgetting to forward options to super silently drops the cause, which is the common mistake when
writing a custom error.
optionssuper
13
The related detail: Error.captureStackTrace in Node removes the constructor frame from the trace, so
the stack starts where the error was thrown rather than inside your error class.
Error.captureStackTrace
14
And the practice worth adopting. Wrap errors at each boundary where you can add context — the repository
knows the query, the service knows the operation, the handler knows the request. Each layer adds a sentence
and keeps the cause. That chain is what turns a stack trace into an explanation.
15
What the interviewer is probing.1. "When would you omit the catch binding?" Probing: the use. Stalls: "Never." Moves up:
when you genuinely do not need the error, such as a feature probe — catch {} is clearer than catch
(e) with an unused variable.
16
2. "What problem does the cause option solve?" Probing: the lost stack. Stalls: "Nothing."
Moves up: rethrowing previously lost the original error; cause attaches it so the chain and its
stack survive.
17
3. "What is wrong with throwing a string?" Probing: the loss. Stalls: "It is shorter."
Moves up: you lose the stack trace and the name, and anything inspecting error.message breaks.
18
4. "How do you define a custom error type?" Probing: the pattern. Stalls: "Return an
object." Moves up: extend Error, set name, and pass options through to super so cause works.