JavaScript’s error handling system has long had a blind spot when dealing with errors across different execution contexts. The new Error.isError()
method addresses this limitation, providing developers with a more reliable way to identify error objects.
Error.isError()
Limited availability
Supported in Chrome: yes.
Supported in Edge: yes.
Supported in Firefox: no.
Supported in Safari: no.
This feature is not Baseline because it does not work in some of the most widely-used browsers.
The traditional approach to checking if a value is an Error has been using the instanceof
operator.
try { // Code that might throw} catch (e) { if (e instanceof Error) { // Handle error }}
This approach has two significant limitations:
- Cross-realm errors aren’t correctly identified. When an error originates from another realm (like an iframe or VM module),
instanceof Error
returnsfalse
because each realm has its ownError
constructor.
const iframe = document.createElement('iframe');document.body.appendChild(iframe);const iframeError = iframe.contentWindow.Error;
// error in the iframe realmconst crossRealmError = new iframeError('Error from iframe');
// This check fails, even though it's clearly an errorconsole.log(crossRealmError instanceof Error); // false 🔴
// Error.isError() correctly identifies itconsole.log(Error.isError(crossRealmError)); // true 🟢
This can lead to situations where errors are not handled correctly, as the instanceof
check fails.
- Fake errors can pass the test. Objects with
Error.prototype
in their prototype chain but lacking error characteristics will be incorrectly identified as errors.
// "fake" error by setting Error.prototype in the prototype chainconst fakeError = { message: "I'm not a real error" };Object.setPrototypeOf(fakeError, Error.prototype);
// This incorrectly identifies it as an Errorconsole.log(fakeError instanceof Error); // true 🔴
// Error.isError() correctly rejects itconsole.log(Error.isError(fakeError)); // false 🟢
These issues can lead to inconsistent error handling and difficult-to-diagnose bugs. The new Error.isError()
method provides a solution:
try { // Code that might throw} catch (e) { if (Error.isError(e)) { // Handle error with confidence }}
Instead of checking the prototype chain, Error.isError()
uses a simpler and more reliable approach. It looks for a special internal marker (like a hidden ID tag) that gets added to every genuine Error
object when it’s created.
This method works better than instanceof
for two reasons:
- It correctly identifies errors even when they come from different contexts (like iframes or modules)
- It rejects fake objects that try to pretend they’re errors by manipulating the prototype
Think of it like checking for a manufacturer’s watermark instead of just looking at the label - it’s much harder to fake.
Typing Error.isError()
Here’s one way you could type the Error.isError()
method in TypeScript:
try {} catch (e: unknown) { // Code that might throw if (Error.isError(e)) { // Here 'e' is narrowed to type Error console.log(e.message); // This is now type-safe } else { // Handle non-Error exceptions console.log("Non-error was thrown:", e); }}