JavaScript の Error.isError() を解説
Error.isError()はrealmをまたぐ本物のJavaScriptエラーを判定し、instanceof Errorより優れる理由と安全なフォールバックを解説します。
Error.isError(value) は静的メソッドで、value が正真正銘の Error オブジェクトである場合にのみ true を返します。プロトタイプチェーンをたどるのではなく内部ブランド([[ErrorData]])をチェックするため、レルムをまたいでも信頼性が保たれます。
エラートラッカーを開いたら、本来なら実際の例外が表示されるべき場所に空の {} が並んでいた、という経験があるなら、あなたはすでにこのメソッドが解決する問題に遭遇しています。どこかの経路で、instanceof チェックが黙ってそのエラーを「エラーではない」と判定したのです。このメソッドは ECMAScript 2026 で標準化されました。つまり、instanceof Error が長年抱えてきた欠陥(iframe 由来のエラーがエラーとして認識されない、逆に偽のオブジェクトがエラーとして認識される)に、ようやく一級の解決策が用意されたということです。本記事では、このメソッドが何をするのか、なぜ instanceof より優れているのか、その背後にある正確なメカニズム、エッジケース、そして安全なフォールバックを伴う導入方法を解説します。
挙動は期待どおりです。Error.isError(new Error()) は true、Error.isError({ message: 'x' }) は false になります。このメソッドは、オブジェクトが何を継承しているかではなく、どのように構築されたかを検証するからです。
要点
Error.isError()は内部スロット[[ErrorData]]に対するブランドチェックを行います。これはArray.isArray()が使うのと同じ、偽装不可能な種類のチェックであり、ユーザーランドのコードがすり抜けることはできません。instanceof Errorは正反対の 2 通りの形で失敗します。別レルムで生成された本物のエラーに対してfalseを返し、プロトタイプをError.prototypeに差し替えた偽オブジェクトに対してtrueを返します。- このメソッドは、
TypeErrorなどの組み込みサブクラス、正しくextend Errorしたクラス、そしてブラウザーにおけるDOMExceptionに対してtrueを返します。ただし Safari は現時点でDOMExceptionに対してfalseを返します。 Error.isError()は ECMAScript 2026 の一部であり、Chrome/Edge 134+、Firefox 138+、Node.js 24.0.0+、Safari 18.4(部分対応)で利用できます。- グローバルハンドラー、ロギングのつなぎ込み、worker、iframe、SSR/エッジといった境界部分で使いましょう。こうした場所では、
instanceofの取りこぼしが黙って本物のエラーをログ上の空オブジェクトに変えてしまいます。
なぜ instanceof Error では不十分なのか
Discover how at OpenReplay.com.
instanceof Error は正反対の 2 通りの形で失敗し、しかもどちらも静かに起こります。TC39 のプロポーザルは 1 つ目を明確に説明しています。iframe 由来であれ Node の vm モジュール由来であれ、レルム境界を越えてきた本物のエラーは偽陰性として返ってきます。各レルムは独自の Error コンストラクターを持つため、iframe 内で生成されたエラーは あなたの Error のインスタンスではないのです。
2 つ目の失敗はその逆です。プロトタイプチェーンに Error.prototype を持つオブジェクトであれば、実際にはエラーでなくてもチェックを通過してしまいます。以下、それぞれの失敗をコードで示します。
// Failure 1 — cross-realm error reads as NOT an error
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const crossRealmError = new iframe.contentWindow.Error('from iframe');
crossRealmError instanceof Error; // → false (wrong)
Error.isError(crossRealmError); // → true (correct)
// Failure 2 — fake object reads as an error
const fake = { message: "I'm not real" };
Object.setPrototypeOf(fake, Error.prototype);
fake instanceof Error; // → true (wrong)
Error.isError(fake); // → false (correct)
どちらの結果も偶然ではなく、仕様として文書化された契約です。MDN のこのメソッドのリファレンスは、まさにこれら双方の失敗モードを回避するがゆえに、instanceof Error に代わる堅牢な選択肢として本メソッドを紹介しています。プロトタイプを借用しただけではチェックを通過できず、他のレルムで作られたエラーであっても通過するのです。instanceof はプロトタイプチェーンに沿ってコンストラクターの同一性を比較するため、この 2 つのケースの両方で誤った結果を出します。
| 入力 | instanceof Error | ダックタイピング('message' in x) | Error.isError() |
|---|---|---|---|
クロスレルムの Error(iframe/worker/vm) | ❌ false | ⚠️ 場合による | ✅ true |
Object.setPrototypeOf(obj, Error.prototype) | ❌ true | ⚠️ true | ✅ false |
class MyError extends Error のインスタンス | ✅ true | ✅ true | ✅ true |
Error.isError() は内部でどう動いているのか
内部的には、Error.isError() はプロトタイプチェーンを調べるのではなく、内部スロットに対するブランドチェックを行います。MDN はこのメカニズムを直接的に説明しています。このメソッドは、Error() コンストラクターが生成するすべてのエラーに設定するプライベートフィールドを探します。これは Array.isArray() の背後にあるのとまったく同じ手法であり、in 演算子がプロパティを検査する仕組みとも近縁です。
この Array.isArray() との類比が、そのままメンタルモデルになります。Array.isArray() もまた、別レルムで作られた配列を受け付けます。各レルムが別々の Array コンストラクターを持つため、instanceof Array はそうした配列に対して false を報告します。Error.isError() は、この同じレルム安全なブランディングをエラーにもたらします。
Stage 4 の仕様テキストはこのスロットを [[ErrorData]] と名付け、IsError 操作をわずか 3 ステップに保っています。オブジェクトでないものは即座に失敗、スロットを持つものは通過、それ以外はすべて失敗です。スロットは構築時に設定され、JavaScript から偽造することはできません。
なぜ Object.prototype.toString ではなくスロットなのか。それは、タグの偽装が旧来の手法を壊してしまったからです。プロポーザルの提案者はこの問題を委員会に持ち込みました。Symbol.toStringTag が登場した時点で、それまで信頼でき、かつ偽装不可能だったチェックは、そのどちらでもなくなったのです。そして Object#toString 以外の何ものもエラースロットを参照しなかったため、ユーザーコードには信頼できる判定手段が一切残されませんでした。Error.isError() はまさにそのギャップを埋めます。
知っておく価値のある挙動の詳細
Error.isError() はエラーファミリー全体に対して true を返し、それ以外のすべてに対して false を返します。例外を投げることはありません。MDN の例では、new Error()、new TypeError()、new DOMException() がいずれも true を返す一方、引数なしの呼び出しや、{}、null、undefined、17、文字列 "Error" を渡した場合は false を返します。仕様上の述語は、オブジェクトでないもの、およびスロットを持たないオブジェクトに対して false を返すため、プリミティブや null は例外を発生させることなくきれいに処理されます。
正しく拡張されたカスタムクラスは、ブランドを継承するため検出されます。
class ValidationError extends Error {}
Error.isError(new ValidationError('bad input')); // → true
拒否されるのは、Error コンストラクターを一度も呼び出していない「見た目だけそっくり」なオブジェクトだけです。DOMException のケースには、覚えておく価値のある微妙な点があります。MDN のルールでは DOMException のインスタンスは通過します。DOMException は、そのコンストラクターが Error コンストラクターを継承していないため、形式的には Error のサブクラスではありません。しかし同じブランドを備えているため、ブランドチェックはこれをエラーとして扱います。例外は Safari です。Chrome による Firefox 138 がリリースされた月のまとめには、Safari が DOMException に対して false を返すと記録されており、すべての主要エンジンが実装済みであるにもかかわらず、このメソッドが Baseline に到達していない理由となっています。MDN も同じ理由で、依然として limited availability(限定的な利用可能性)と表示しています。このケースだけは「まだ統一されていない」ものとして扱ってください。
Error.isError() を使うべき場面
Error.isError() は境界部分(グローバルエラーハンドラー、ロギングやエラーレポートのつなぎ込み、テストランナー、ライブラリー、SSR/エッジ、worker、iframe、ブラウザー拡張機能)で使いましょう。これらの場所では、instanceof の取りこぼしが黙って本物のエラーをログ上の空の {} に変えてしまいます。スコープが厳密に閉じた同一レルム内のコードであれば、素の instanceof で問題ありません。効果が出るのは、値が実行コンテキストをまたぐ境界部分に限られます。
これは実際のレポーティング上の障害パターンに対応します。境界での instanceof チェックが、本当にスローされたエラーを単なるプレーンオブジェクトとして再分類してしまい、メッセージもスタックもない状態でパイプラインに流れ込むのです。ここではセッションリプレイが有用な手法になります。セッションを再生すれば、実際にスローされたコンソールエラーが浮かび上がり、ブラウザーが見たものとつなぎ込みコードが報告したものとのギャップが明らかになります。解決策は、シリアライズやロギングが行われる前に、それらの境界で Error.isError() によるブランドチェックを行うことです。
ブラウザー・ランタイムのサポート状況と安全なフォールバック
Error.isError() は ECMAScript 2026(第 17 版)の一部であり、Ecma International が 2026 年 6 月 30 日に承認しました。プロポーザルは 2025 年 5 月の TC39 会議で Stage 4 に到達しています。ブラウザーでは Chrome および Edge 134、Safari 18.4、そして 2025 年 4 月 29 日にリリースされた Firefox 138 から利用できます。サーバーサイドでは、Node.js 24.0.0 が V8 13.6 へのアップグレードによってこれを取り込み、Float16Array、明示的リソース管理、RegExp.escape、WebAssembly Memory64 とともに導入されました。
古い環境でも穏やかに劣化するドロップイン方式のアップグレードには、機能検出を使います。
function isError(value) {
return typeof Error.isError === 'function'
? Error.isError(value) // realm-safe on modern engines
: value instanceof Error; // fallback, not realm-safe
}
TypeScript では、Error.isError(e) は型ガードとしても機能し、unknown としてキャッチされた値を if ブロック内で Error に絞り込みます。そのため、手動キャストなしに e.message を型安全に扱えます。
まとめ
Error.isError() は、ダックタイピングや instanceof では決して埋められなかったギャップを埋めます。エンジンが実際にその値をエラーとしてブランド付けしたかどうかを問うため、クロスレルムのエラーもプロトタイプを偽装した偽物も、正しく判定されます。境界部分のチェック(ロギングのつなぎ込み、グローバルハンドラー、worker や iframe の継ぎ目)を、今日から機能検出付きのラッパーに置き換えましょう。instanceof は、コードが自身のレルムから決して出ない場所にだけ残せば十分です。
FAQ
Error.isError() は標準化されているのですか、それともまだ実験的なプロポーザルですか?
Error.isError() は完全に標準化されています。2025 年 5 月の第 108 回会議で TC39 プロセスの Stage 4 に進み、言語仕様の第 17 版である ECMAScript 2026 に含まれています。もはやプロポーザルでも実験的機能でもないため、「まだ標準化されていない」「Stage 3」といった説明は古い情報です。すでに出荷済みの言語機能として扱ってください。
Error.isError() はカスタムエラークラスでも動作しますか?
はい。クラスが正しく Error を拡張している限り動作します。'class MyError extends Error {}' として定義されたクラスは、Error コンストラクターが設定する内部ブランドを継承するため、Error.isError(new MyError()) は true を返します。拒否されるのは、Error コンストラクターを一度も呼び出していない見た目だけそっくりなオブジェクト、たとえばプロトタイプチェーンに Error.prototype を無理やり差し込んだプレーンオブジェクトだけです。要件はクラス名ではなく、正しくサブクラス化されていることです。
Error.isError() は Safari で動作しますか?
Safari 18.4 以降は通常の Error オブジェクトについて Error.isError() をサポートしていますが、サポートは部分的です。Safari は現時点で DOMException のインスタンスに対して false を返しますが、仕様および他のエンジンは true を返します。このギャップのため、MDN はこのメソッドを Baseline に分類しておらず、web.dev も一様には利用可能でないとしています。Safari を対象とするコードでは、DOMException のケースを防御的に扱ってください。
Error.isError() は instanceof Error より高速ですか?
どちらも実質的に定数時間のチェックであるため、パフォーマンスは移行の理由になりません。instanceof はプロトタイプチェーンをたどり、Error.isError() は単一の内部ブランドを読み取りますが、実用上の差は無視できる程度です。本当の利点は正しさにあります。Error.isError() は、instanceof が黙って失敗するクロスレルムのエラーやプロトタイプを偽装した偽物に対して、正しい答えを返します。速度ではなく、実行コンテキスト境界での信頼性のために選んでください。
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Star on GitHub12k