How Lodash isError Identifies Custom Errors
This article examines how the Lodash utility function
_.isError evaluates custom error objects, addressing
specifically whether stack trace properties are inspected during type
detection. You will learn the exact internal validation steps Lodash
uses, why stack trace properties like stack are completely
omitted from verification, and how custom error classes must be
structured to be recognized by the library.
The Short Answer: Stack Properties Are Not Verified
Despite common assumptions, _.isError does not
verify any stack trace properties. It does not check for the
presence, format, or type of error.stack,
error.stackTraceLimit, or V8 methods like
Error.captureStackTrace.
Because the stack property is historically non-standard
and varies significantly across JavaScript runtimes (browsers, Node.js,
and embedded engines), Lodash avoids relying on stack trace metadata
entirely.
How
_.isError Actually Evaluates Errors
Lodash implements a multi-step check to identify standard errors, DOM exceptions, and custom error classes across different execution realms (such as iframes or worker threads).
The source code evaluates objects using the following logic:
function isError(value) {
if (!isObjectLike(value)) {
return false;
}
var tag = baseGetTag(value);
return tag == errorTag || tag == domExcTag ||
(typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
}1. Object Verification
The candidate must satisfy isObjectLike(value), meaning
the value must not be null and its typeof
evaluation must be 'object'.
2. Internal Tag Matching
Lodash first checks the internal [[Class]] tag via
Object.prototype.toString.call(value):
[object Error]matches standard built-in error instances (Error,TypeError,RangeError, etc.).[object DOMException]matches browser DOM exceptions.
3. Duck-Typing Fallback for Custom Errors
When a custom error class does not produce the
[object Error] tag—often the case with transpiled ES5
classes, manual prototypical inheritance, or custom objects overriding
Symbol.toStringTag—Lodash applies a structural duck-typing
check:
typeof value.message === 'string': The object must contain a stringmessageproperty.typeof value.name === 'string': The object must contain a stringnameproperty.!isPlainObject(value): The object must not be a plain object literal ({}). It must have an inherited prototype chain or a prototype not directly pointing toObject.prototypeornull.
Why Lodash Avoids
Checking the stack Property
Lodash deliberately omits stack checks for several
technical reasons:
- ECMAScript Specification: The ECMAScript standard
does not mandate a
stackproperty onError.prototype. While standard in modern engines, it remains implementation-dependent. - Lazy Stack Evaluation: Modern JavaScript engines
like V8 implement
stackas a getter function that formats the stack trace on access. Inspectingstackduring a generic type check can trigger unnecessary performance overhead. - Absence in Specific Environments: Some minimal or legacy runtimes do not generate stack traces automatically when an error object is instantiated.
Creating Compatible Custom Error Classes
To guarantee that a custom error class is identified by
_.isError, ensure it inherits from Error or
satisfies the structural criteria:
class CustomAppError extends Error {
constructor(message) {
super(message);
this.name = 'CustomAppError';
}
}
// Satisfies the internal tag check and inherits from Error
_.isError(new CustomAppError('Failure')); // trueIf constructing a simulated error without inheriting directly from
Error, satisfy the duck-typing fallback:
function CustomProtoError(message) {
this.name = 'CustomProtoError';
this.message = message;
}
CustomProtoError.prototype = Object.create(Object.prototype);
// Passes because name and message are strings, and it is not a plain object literal
_.isError(new CustomProtoError('Failure')); // trueOmitting stack entirely from your custom error
implementations will have no negative impact on detection by
_.isError.