Start · Sprachen · JavaScript · Referenz · Error.prototype.stack

Error.prototype.stack

Eigenschaft

Liefert als String einen Stacktrace: welche Funktionen in welcher Reihenfolge aufgerufen wurden, samt Datei, Zeile und Spalte, an der der Fehler erzeugt wurde.

seit JavaScript Nicht standardisiert – Baseline: alle modernen Bro Kategorie: method-property

Signatur

error.stack

Beschreibung

Die Eigenschaft stack einer Error-Instanz enthält eine textuelle Rückverfolgung des Aufrufstapels (Stacktrace) zu dem Zeitpunkt, an dem das Fehlerobjekt erzeugt wurde – nicht dem Zeitpunkt, an dem es geworfen wird. Jede Zeile beschreibt einen Stack-Frame, meist mit Funktionsname, Datei-URL, Zeilen- und Spaltennummer. Aktuelle Engines geben die Argumentwerte der Funktionen nicht mehr aus.

Gebraucht wird stack vor allem zum Debuggen und Protokollieren: in Log-Dateien, bei Fehler-Monitoring-Diensten (z. B. Sentry) oder in globalen Fehlerbehandlern wie window.onerror und process.on("uncaughtException"). So lässt sich auch bei Fehlern im Produktivbetrieb nachvollziehen, woher sie stammen.

Die Eigenschaft ist nicht Teil des ECMAScript-Standards (ein Vorschlag „Error Stacks“ ist in Arbeit). Deshalb unterscheidet sich das Format zwischen den Engines: V8 (Chrome, Edge, Node.js, Deno) beginnt mit Name: Nachricht und listet danach Zeilen der Form at fn (datei:zeile:spalte). SpiderMonkey (Firefox) und JavaScriptCore (Safari) nutzen dagegen fn@datei:zeile:spalte und lassen die Kopfzeile weg. In V8 ist stack eine eigene Eigenschaft der Instanz, in Firefox ein Accessor auf Error.prototype.

Die Eigenschaft ist beschreibbar. Das ist praktisch, um Stacktraces anzupassen oder zu kürzen. Wer Stacktraces maschinell auswerten will, sollte sich aber nie auf ein festes Format verlassen.

Rückgabewert

Typ
string | undefined
Beschreibung
Ein mehrzeiliger String mit dem Stacktrace. Bei Objekten, die keine echten Fehlerinstanzen sind, oder in sehr alten Umgebungen kann der Wert undefined sein.

Beispiele

Stacktrace eines abgefangenen Fehlers ausgeben

const ladeBenutzer = (id) => {
  if (typeof id !== "number") {
    throw new TypeError(`Ungültige ID: ${id}`);
  }
  return { id };
};

const init = () => ladeBenutzer("abc");

try {
  init();
} catch (err) {
  console.log(err.stack);
}
// V8 (Chrome/Node.js): TypeError: Ungültige ID: abc at ladeBenutzer (app.js:3:11) at init (app.js:8:20) at app.js:11:3 // Firefox: ladeBenutzer@app.js:3:11 init@app.js:8:20 @app.js:11:3

Eigene Fehlerklasse mit sauberem Stacktrace

class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
    // Konstruktor-Frame aus dem Stack entfernen (V8, neuere Firefox/Safari)
    if (typeof Error.captureStackTrace === "function") {
      Error.captureStackTrace(this, ValidationError);
    }
  }
}

const pruefeEmail = (email) => {
  if (!email.includes("@")) {
    throw new ValidationError("E-Mail ungültig", "email");
  }
};

try {
  pruefeEmail("max.example.com");
} catch (err) {
  console.log(err.stack.split("\n")[0]);
}
ValidationError: E-Mail ungültig

Fehler für das Logging aufbereiten

const serialisiereFehler = (err) => ({
  name: err?.name ?? "UnknownError",
  message: err?.message ?? String(err),
  // stack kann fehlen – etwa wenn ein String geworfen wurde
  stack: err instanceof Error ? err.stack : undefined,
  zeit: new Date().toISOString(),
});

const sendeLog = async (eintrag) => {
  await fetch("/api/logs", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(eintrag),
  });
};

window.addEventListener("error", (event) => {
  sendeLog(serialisiereFehler(event.error));
});

window.addEventListener("unhandledrejection", (event) => {
  sendeLog(serialisiereFehler(event.reason));
});

Stacktrace-Tiefe in Node.js erhöhen

// Standard in V8: 10 Frames
Error.stackTraceLimit = 50;

const rekursiv = (n) => {
  if (n === 0) throw new Error("Tief unten");
  rekursiv(n - 1);
};

try {
  rekursiv(30);
} catch (err) {
  const frames = err.stack.split("\n").filter((z) => z.trim().startsWith("at "));
  console.log(`Anzahl Frames: ${frames.length}`);
}
Anzahl Frames: 33

// Wichtig · Fallstricke

  • Nicht standardisiert: Format, Kopfzeile und Anzahl der Frames hängen von der Engine ab. Wer Stacktraces zuverlässig parsen will, sollte eine Bibliothek wie stacktrace-parser oder error-stack-parser verwenden, statt eigene reguläre Ausdrücke zu schreiben.
  • Erzeugung statt Wurf: Der Stack wird festgehalten, wenn new Error() aufgerufen wird. Wer ein Fehlerobjekt vorab erzeugt und erst später wirft, bekommt den Stack der Erzeugung.
  • Nur bei echten Fehlern: Mit throw "Text" oder throw {} geworfene Werte haben keinen stack. Deshalb immer Instanzen von Error werfen.
  • Kopfzeile in V8: Die Zeile Name: Nachricht wird beim ersten Zugriff auf stack gebildet. Wer name oder message erst danach ändert, sieht die Änderung nicht im Stack.
  • Asynchroner Code: Über await hinweg zeigen V8 (async stack traces) und die DevTools die Frames zum Teil an, bei setTimeout- oder Callback-Ketten fehlen sie meist. Mit Error.prototype.cause (ES2022) lassen sich Fehlerketten erhalten.
  • Gebündelter oder minifizierter Code: Zeilen- und Spaltenangaben beziehen sich auf den ausgelieferten Code. Um sie auf die Originalquellen zurückzuführen, braucht man Source Maps (in Node.js z. B. über --enable-source-maps).
  • Sicherheit: Stacktraces verraten Dateipfade, interne Modulnamen und den Aufbau der Anwendung. Zeige sie deshalb nie Endnutzern an und gib sie in HTTP-Antworten von Servern nicht nach außen. Protokolliere sie nur intern.
  • Performance: Einen Stacktrace zu erfassen kostet Zeit. Ein höheres Error.stackTraceLimit (nur V8) macht jede Fehlererzeugung teurer.