12k
All articles

Error.isError() en JavaScript : explications

Error.isError() vérifie les vraies erreurs JavaScript entre realms, explique pourquoi il surpasse instanceof Error et propose un repli sûr.

OpenReplay Team
OpenReplay Team
Error.isError() en JavaScript : explications

Error.isError(value) est une méthode statique qui renvoie true uniquement lorsque value est un véritable objet Error, et elle reste fiable même d’un realm à l’autre, car elle vérifie une marque interne ([[ErrorData]]) plutôt que de parcourir la chaîne de prototypes.

Si vous avez déjà ouvert votre outil de suivi d’erreurs pour y trouver un {} vide là où aurait dû se trouver une véritable exception, vous connaissez déjà le problème que cette méthode résout. Quelque part en chemin, une vérification instanceof a discrètement décrété que votre erreur n’en était pas une. Cette méthode a été normalisée dans ECMAScript 2026, ce qui signifie que les lacunes de longue date d’instanceof Error (des erreurs provenant d’iframes considérées comme des non-erreurs, et de faux objets considérés comme des erreurs) disposent désormais d’une solution de premier ordre. Cet article explique ce que fait la méthode, pourquoi elle surpasse instanceof, le mécanisme exact qui la sous-tend, ses cas limites, et comment l’adopter avec un fallback sûr.

Le comportement est exactement celui auquel on s’attend : Error.isError(new Error()) renvoie true, et Error.isError({ message: 'x' }) renvoie false, car la méthode vérifie la façon dont l’objet a été construit, et non simplement ce dont il hérite.

Points clés à retenir

  • Error.isError() effectue une vérification par marquage (branded check) du slot interne [[ErrorData]], la même catégorie de vérification infalsifiable qu’utilise Array.isArray() ; le code utilisateur ne peut donc pas la contourner par usurpation.
  • instanceof Error échoue de deux manières opposées : false pour une véritable erreur créée dans un autre realm, et true pour un faux objet dont le prototype a été fixé à Error.prototype.
  • La méthode renvoie true pour les sous-classes natives comme TypeError, pour les classes qui étendent correctement Error, et pour DOMException dans les navigateurs — bien que Safari renvoie actuellement false pour DOMException.
  • Error.isError() fait partie d’ECMAScript 2026 et est disponible dans Chrome/Edge 134+, Firefox 138+, Node.js 24.0.0+, et Safari 18.4 (partiellement).
  • Utilisez-la aux frontières (gestionnaires globaux, couches de logging, workers, iframes, SSR/edge) où un échec silencieux d’instanceof transforme une véritable erreur en objet vide dans vos logs.

Pourquoi instanceof Error est-il insuffisant ?

instanceof Error échoue de deux manières opposées, et les deux sont silencieuses. La proposition TC39 détaille la première : une véritable erreur ayant franchi une frontière de realm, que ce soit depuis une iframe ou depuis le module vm de Node, produit un faux négatif. Chaque realm possède son propre constructeur Error, si bien qu’une erreur créée dans une iframe n’est pas une instance de votre Error.

Le second échec est l’inverse : n’importe quel objet ayant Error.prototype dans sa chaîne passe la vérification sans être une véritable erreur. Voici chaque cas d’échec en code :

// 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)

Ces deux résultats relèvent du contrat documenté et non d’un accident. La référence MDN de la méthode la présente comme l’alternative robuste à instanceof Error précisément parce qu’elle évite chacun de ces modes de défaillance : un prototype emprunté ne suffit pas à passer la vérification, et une erreur construite dans un autre realm la passe malgré tout. instanceof compare l’identité du constructeur le long de la chaîne de prototypes, il se trompe donc dans les deux cas.

Entréeinstanceof Errorduck-typing ('message' in x)Error.isError()
Error cross-realm (iframe/worker/vm)false⚠️ variabletrue
Object.setPrototypeOf(obj, Error.prototype)true⚠️ truefalse
Instance de class MyError extends Errortruetruetrue

Comment fonctionne Error.isError() en interne ?

En interne, Error.isError() effectue une vérification par marquage d’un slot interne plutôt qu’une inspection de la chaîne de prototypes. MDN décrit directement le mécanisme : la méthode recherche un champ privé que le constructeur Error() installe sur chaque erreur qu’il construit. C’est exactement l’astuce derrière Array.isArray(), et une proche cousine de la façon dont l’opérateur in teste la présence d’une propriété.

Cette analogie avec Array.isArray() est le bon modèle mental à conserver. Array.isArray() accepte également les tableaux construits dans un realm différent, là où instanceof Array renvoie false puisque chaque realm détient un constructeur Array distinct. Error.isError() apporte ce même marquage compatible entre realms aux erreurs.

Le texte de spécification en Stage 4 nomme le slot [[ErrorData]] et limite l’opération IsError à trois étapes : tout ce qui n’est pas un objet échoue immédiatement, tout ce qui porte le slot réussit, et tout le reste échoue. Le slot est défini à la construction et ne peut pas être falsifié depuis JavaScript.

Pourquoi un slot plutôt qu’Object.prototype.toString ? Parce que l’usurpation de tag a cassé l’ancienne astuce. L’auteur de la proposition a porté le problème devant le comité : dès lors que Symbol.toStringTag a existé, une vérification qui était à la fois fiable et impossible à falsifier a cessé d’être l’un comme l’autre. Et puisque rien en dehors d’Object#toString ne consultait jamais le slot d’erreur, le code utilisateur se retrouvait sans aucun test fiable. Error.isError() comble exactement cette lacune.

Détails de comportement à connaître

Error.isError() renvoie true pour toute la famille des erreurs et false pour tout le reste, sans jamais lever d’exception. Les exemples de MDN montrent que new Error(), new TypeError() et new DOMException() renvoient tous true, tandis qu’un appel sans argument, ou avec {}, null, undefined, 17, ou la chaîne "Error", renvoie false. Comme le prédicat de la spécification renvoie false pour tout non-objet et pour les objets dépourvus du slot, les primitives et null sont traités proprement plutôt que de provoquer une erreur.

Les classes personnalisées correctement étendues sont détectées, puisqu’elles héritent de la marque :

class ValidationError extends Error {}
Error.isError(new ValidationError('bad input')); // → true

Seuls les sosies qui n’appellent jamais le constructeur Error sont rejetés. Le cas de DOMException comporte une nuance qu’il vaut la peine de mémoriser. La règle énoncée par MDN est que les instances de DOMException passent la vérification. DOMException n’est pas formellement une sous-classe d’Error, car son constructeur n’hérite pas du constructeur Error, mais elle porte la même marque : les vérifications par marquage la traitent donc comme une erreur. Safari fait exception : le récapitulatif Chrome du mois où Firefox 138 est sorti indique que Safari répond false pour DOMException, raison pour laquelle la méthode n’a pas atteint le statut Baseline alors même que tous les moteurs majeurs l’implémentent désormais. MDN la classe toujours en disponibilité limitée pour la même raison. Considérez ce cas particulier comme non encore uniforme.

Quand utiliser Error.isError()

Utilisez Error.isError() aux frontières (gestionnaires d’erreurs globaux, couches de logging et de reporting d’erreurs, test runners, bibliothèques, SSR/edge, workers, iframes et extensions de navigateur) où un échec silencieux d’instanceof transforme une véritable erreur en {} vide dans vos logs. Un simple instanceof reste acceptable dans du code étroitement circonscrit à un seul realm ; le bénéfice se situe spécifiquement aux frontières où les valeurs franchissent des contextes d’exécution.

Cela correspond à un mode de défaillance de reporting bien réel : une vérification instanceof placée à une frontière reclasse une véritable erreur lancée en simple objet, qui atterrit alors dans votre pipeline sans message ni stack trace. Le session replay est une technique utile ici : rejouer la session fait apparaître l’erreur console réellement levée, révélant l’écart entre ce que le navigateur a vu et ce que votre code de liaison a rapporté. La solution consiste à effectuer une vérification par marquage avec Error.isError() à ces frontières, avant toute sérialisation ou journalisation.

Prise en charge par les navigateurs et les runtimes, et fallback sûr

Error.isError() fait partie d’ECMAScript 2026, la 17e édition, ratifiée par Ecma International le 30 juin 2026 ; la proposition a atteint le Stage 4 lors de la réunion TC39 de mai 2025. Côté navigateurs, elle fonctionne à partir de Chrome et Edge 134, Safari 18.4, et Firefox 138, sorti le 29 avril 2025. Côté serveur, Node.js 24.0.0 l’a intégrée via la mise à niveau vers V8 13.6, qui l’a apportée aux côtés de Float16Array, de la gestion explicite des ressources, de RegExp.escape et de WebAssembly Memory64.

Pour une amélioration immédiate qui se dégrade proprement sur les cibles plus anciennes, faites de la détection de fonctionnalité :

function isError(value) {
  return typeof Error.isError === 'function'
    ? Error.isError(value)      // realm-safe on modern engines
    : value instanceof Error;   // fallback, not realm-safe
}

En TypeScript, Error.isError(e) fait également office de type guard : elle restreint une valeur capturée de type unknown à Error à l’intérieur de la branche if, si bien que e.message est typé en toute sécurité sans cast manuel.

Conclusion

Error.isError() comble une lacune que ni le duck-typing ni instanceof n’ont jamais pu combler : elle demande si le moteur a réellement marqué une valeur comme étant une erreur, de sorte que les erreurs cross-realm et les faux objets à prototype usurpé sont tous deux correctement résolus. Migrez dès aujourd’hui vos vérifications aux frontières (couche de logging, gestionnaires globaux, jonctions avec les workers et les iframes) vers le wrapper à détection de fonctionnalité, et réservez instanceof aux endroits où le code ne quitte jamais son propre realm.

FAQ

Error.isError() est-elle normalisée ou toujours à l'état de proposition expérimentale ?

Error.isError() est entièrement normalisée. Elle est passée au Stage 4 du processus TC39 lors de la 108e réunion en mai 2025 et est incluse dans ECMAScript 2026, la 17e édition de la spécification du langage. Ce n'est plus une proposition ni une fonctionnalité expérimentale : les descriptions la qualifiant de « non encore normalisée » ou de « Stage 3 » sont obsolètes. Considérez-la comme une fonctionnalité du langage pleinement livrée.

Error.isError() fonctionne-t-elle avec les classes d'erreur personnalisées ?

Oui, à condition que la classe étende correctement Error. Une classe définie par 'class MyError extends Error {}' hérite de la marque interne posée par le constructeur Error, si bien qu'Error.isError(new MyError()) renvoie true. Seuls les objets sosies qui n'appellent jamais le constructeur Error, comme un objet simple auquel on a forcé Error.prototype dans sa chaîne, sont rejetés. C'est le sous-classement correct qui compte, pas le nom de la classe.

Error.isError() fonctionne-t-elle dans Safari ?

Safari 18.4 et versions ultérieures prennent en charge Error.isError() pour les objets Error classiques, mais la prise en charge est partielle. Safari renvoie actuellement false pour les instances de DOMException, alors que la spécification et les autres moteurs renvoient true. En raison de cet écart, MDN ne classe pas la méthode comme Baseline, et web.dev la signale comme n'étant pas encore uniformément disponible. Traitez le cas DOMException de manière défensive si votre code cible Safari.

Error.isError() est-elle plus rapide qu'instanceof Error ?

Les deux sont, en pratique, des vérifications à temps constant : la performance n'est donc pas la raison de migrer. instanceof parcourt la chaîne de prototypes tandis qu'Error.isError() lit une unique marque interne, mais la différence pratique est négligeable. Le véritable avantage est la justesse : Error.isError() donne la bonne réponse pour les erreurs cross-realm et les faux objets à prototype usurpé, cas où instanceof échoue silencieusement. Choisissez-la pour sa fiabilité aux frontières entre contextes d'exécution, pas pour sa vitesse.

Open-source session replay

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

We use cookies to improve your experience. By using our site, you accept cookies.