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.
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.stackTraceLimitvaut 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.
function lancerPlusTard() {
setTimeout(() => { throw new Error("dans le minuteur"); }, 0);
}
lancerPlusTard();
// La trace ne mentionne pas lancerPlusTard : il a déjà quitté la pileDeux 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.
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
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é.
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.
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.