Stack trace en JavaScript : lire la pile d'appels d'une erreur

La trace d'appels d'une erreur dit par où le programme est passé avant de casser : comment la lire, ce que l'asynchrone efface, et comment la garder utile.
3 min de lecture
Believemy logo

Un message d'erreur dit ce qui a cassé. La trace d'appels dit comment on en est arrivé là, et c'est presque toujours l'information qui manque pour corriger.

Encore faut-il la lire dans le bon sens, et savoir ce qu'elle ne contient pas.


Définition

La trace d'appels est le texte porté par la propriété stack d'un objet Error. Elle liste les fonctions traversées, de la plus récente à la plus ancienne, avec fichier, ligne et colonne.

JAVASCRIPT
function niveau3() { throw new Error("rien ne va"); }
function niveau2() { niveau3(); }
function niveau1() { niveau2(); }

try {
  niveau1();
} catch (err) {
  console.log(err.stack);
}

// Error: rien ne va
//     at niveau3 (index.js:1:28)
//     at niveau2 (index.js:2:22)
//     at niveau1 (index.js:3:22)

La première ligne reprend le nom et le message, les suivantes se lisent de haut en bas comme un retour en arrière. La ligne du haut est l'endroit de la rupture, celles du bas racontent l'enchaînement qui y a mené.


Ce qu'elle vous dit vraiment

  • La trace est capturée à la création. Elle décrit l'endroit du new Error, pas celui du throw ni celui du catch. Créer l'erreur loin de l'incident détruit l'information.
  • Elle s'arrête à une profondeur fixe. Sous Node.js et dans les navigateurs fondés sur le même moteur, Error.stackTraceLimit vaut dix par défaut et peut être augmenté en développement.
  • Son format n'est pas normalisé. Il varie d'un moteur à l'autre : utile pour lire et journaliser, jamais à analyser comme une donnée structurée.


Ce que l'asynchrone efface

Une erreur levée dans un callback de minuteur ou de requête part d'une pile presque vide : le code appelant a rendu la main depuis longtemps et n'apparaît plus.

JAVASCRIPT
function lancerPlusTard() {
  setTimeout(() => { throw new Error("dans le minuteur"); }, 0);
}

lancerPlusTard();
// La trace ne mentionne pas lancerPlusTard : il a déjà quitté la pile

Deux réflexes limitent la casse. Préférer await aux callbacks, car les moteurs récents reconstituent la trace au travers des attentes. Et enrichir l'erreur au moment où on l'attrape, en la relançant avec la propriété cause, qui conserve l'erreur d'origine et sa trace.

Bon à savoir

Sur du code minifié, la trace pointe une ligne unique et des noms d'une lettre. Le fichier de correspondance produit à la construction, s'il est fourni à l'outil de suivi des erreurs, retraduit la trace vers les fichiers d'origine. Sans lui, la trace de production est illisible.


Questions fréquentes

Question

Comment retirer les lignes internes d'une trace ?

Avec Error.captureStackTrace(this, MaClasse) dans le constructeur d'une erreur maison : la trace démarre alors chez l'appelant, sans les lignes de la fabrique. La fonction est propre au moteur V8, donc à Node.js et à Chrome, et à protéger par un test de présence dans un code partagé.


Question

Faut-il afficher la trace à l'utilisateur ?

Non. Elle expose des chemins de fichiers et des détails internes sans aucune valeur pour la personne qui utilise le produit. L'écran reçoit un message compréhensible, les journaux reçoivent la trace complète.


Question

Pourquoi ma trace ne contient-elle qu'une seule ligne ?

Souvent parce que l'erreur a été construite ailleurs qu'à l'endroit de l'incident, par exemple à partir d'une chaîne relancée dans un catch. Relancez l'objet d'origine, ou créez la nouvelle erreur avec l'ancienne en cause pour conserver les deux traces.

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.