JavaScript Throw String vs Error Object
In JavaScript, developers can throw any expression, but choosing
between throwing a string literal and an Error object
fundamentally changes how issues are diagnosed and handled. While
throwing a string merely transmits a plain text message, throwing an
Error object captures a full stack trace, standardizes
properties for error handling, and integrates seamlessly with runtime
environments and debugging tools.
The Core Difference: Stack Traces
The most critical distinction is the stack trace. When you
instantiate an Error object, JavaScript automatically
captures a snapshot of the call stack at that exact moment.
Throwing an
Error:throw new Error("Something went wrong");This creates an object containing a
stackproperty. When caught or logged, it shows the exact file, line number, and sequence of function calls that led to the issue.Throwing a String:
throw "Something went wrong";This passes only the primitive string. No call stack is generated. If this exception bubbles up uncaught, or is logged in a generic catch block, you will only see the text with no context regarding where or why the failure occurred.
Predictability in Catch Blocks
Standard error-handling conventions assume that thrown values are
instances of Error. Code written to consume errors
typically accesses standard properties such as err.message
or err.name.
If a string is thrown instead:
try {
throw "Invalid user ID";
} catch (err) {
console.error(err.message); // undefined
console.error(err); // "Invalid user ID"
}Attempting to read err.message returns
undefined, which can cause downstream bugs or result in
silent logging failures. Conversely, an Error object
guarantees that err.message contains the descriptive
text.
Custom and Subclassed Errors
Using Error objects allows you to leverage inheritance
and built-in error types (such as TypeError,
RangeError, or custom subclasses). This enables selective
error handling:
try {
validateInput(data);
} catch (err) {
if (err instanceof ValidationError) {
// Handle expected validation issue
} else {
// Re-throw unexpected system errors
throw err;
}
}Strings cannot be differentiated with instanceof,
forcing you to rely on fragile string matching to identify the error
type.
Asynchronous Code and Promises
When rejecting Promises, the same rule applies. Rejecting with a string causes modern browser consoles and Node.js runtimes to emit warnings about unhandled rejections missing a stack trace:
// Bad practice
Promise.reject("Operation failed");
// Good practice
Promise.reject(new Error("Operation failed"));Summary
Always throw an Error object (or an instance of a class
extending Error) instead of a string literal. Using
Error objects preserves the execution history through stack
traces, ensures consistency across try...catch blocks, and
prevents difficult-to-trace bugs in production environments.