Fehler- und Ladezustände
Was passiert, wenn etwas schiefgeht – und wer es auffängt
error.tsx fängt Fehler eines Bereichs ab, not-found.tsx die fehlenden Adressen. Beides sind Dateien, keine Konfiguration.
Ohne Auffangnetz bedeutet ein Fehler beim Datenladen: weiße Seite. Next.js bringt dafür zwei Dateien mit, die genau wie loading.tsx einfach im Ordner liegen.
error.tsx
"use client"; // Pflicht – error.tsx ist immer eine Client-Komponente
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>Da ist etwas schiefgegangen.</h2>
<button onClick={reset}>Nochmal versuchen</button>
</div>
);
} Die Datei error.tsxFängt Fehler aus dem Bereich darunter ab und zeigt stattdessen etwas Lesbares. Muss eine Client-Komponente sein.→ fängt alles ab, was in ihrem Ordner und darunter beim Rendern schiefgeht. Der Rest der Seite – Layout, Kopfzeile, Navigation – bleibt stehen und bedienbar.
app/blog/error.tsx fängt Fehler aus app/blog/page.tsx ab – aber nicht aus app/blog/layout.tsx. Dafür ist die Ebene darüber zuständig. Wer ein Layout absichern will, braucht das error.tsx eine Stufe höher.
Next.js ersetzt sie durch eine allgemeine Meldung plus eine digest-Kennung, damit nichts Internes nach außen dringt. Über diese Kennung findest du den echten Fehler im Serverprotokoll wieder.
not-found.tsx
import { notFound } from "next/navigation";
export default async function Seite({ params }) {
const { slug } = await params;
const artikel = await ladeArtikel(slug);
if (!artikel) notFound(); // hält hier an und zeigt not-found.tsx
return <article>{artikel.inhalt}</article>;
} not-found.tsxWird gezeigt, wenn eine Adresse nicht existiert oder der Code `notFound()` aufruft.→ greift in zwei Fällen: wenn du notFound() aufrufst, und wenn eine Adresse gar nicht existiert. Beides liefert korrekt den Statuscode 404 – wichtig, damit Suchmaschinen die Seite nicht indexieren.
const artikel = await ladeArtikel(slug);
if (!artikel) throw new Error("Artikel nicht gefunden"); const artikel = await ladeArtikel(slug);
if (!artikel) notFound(); „Gibt es nicht“ ist kein Fehler, sondern ein Ergebnis. Mit throw bekämst du eine 500 und die Fehlerseite – für Suchmaschinen und Nutzer das falsche Signal.
Die Ebenen im Überblick
app/
error.tsx fängt alles, auch Fehler aus app/blog/layout.tsx
global-error.tsx letzter Notnagel, ersetzt auch das Wurzel-Layout
not-found.tsx 404 für die ganze Anwendung
blog/
error.tsx fängt Fehler aus blog/page.tsx und darunter
loading.tsx Platzhalter während des Ladens
page.tsx Weil es das Wurzel-Layout ersetzt, muss es die HTML-Hülle selbst mitbringen. Es greift nur, wenn schon das Wurzel-Layout scheitert – in der Praxis selten, aber der Unterschied erklärt die ungewöhnliche Anforderung.
Erwartete und unerwartete Fehler
- +
notFound()für „gibt es nicht“ - +
Rückgabewerte für Validierungsfehler – etwa aus einer Server Action
- +
error.tsxfür das Unerwartete: Datenbank weg, fremde API antwortet nicht
- −
throwfür alles, was du eigentlich erwartest - −
Fehlerdetails im Browser anzeigen
- −
Auf
error.tsxverzichten und hoffen
▸ Genauer erklärt: Was error.tsx nicht abfängt optional
error.tsx fängt:
✓ Fehler beim Rendern der Seite und darunter
✓ Fehler beim Datenladen in diesen Komponenten
error.tsx fängt NICHT:
✗ Fehler im eigenen Layout → Ebene darüber zuständig
✗ Fehler in Event-Handlern → try/catch im Handler
✗ Fehler in Server Actions → Rückgabewert statt throw
✗ Fehler nach dem Rendern → z. B. in einem setTimeout Für Server Actions ist der Rückgabewert der bessere Weg: return { fehler: "…" } statt throw. So kannst du die Meldung im Formular anzeigen, ohne die ganze Ansicht durch die Fehlerseite zu ersetzen.
Sitzt das schon?
4 Fragen zu dieser Lektion. Falsche Antworten landen in deiner Statistik.
Jetzt selbst schreiben
Baue die Anzeige, die Next.js bei einem Fehler einblendet. Sie zeigt eine allgemeine Meldung und einen Knopf, der den Bereich neu aufbaut. (In Next.js bekäme die Komponente error und reset von außen; hier reichst du reset selbst herein, damit es prüfbar ist.)
- □Die Überschrift
Da ist etwas schiefgegangen.erscheint - □Die technische Fehlermeldung wird nicht angezeigt
- □Ein Klick auf
Nochmal versuchenruftresetauf
import { useState } from "react"; type Props = { error: Error & { digest?: string }; reset: () => void; }; // In Next.js: "use client" + Datei heißt error.tsx export function Fehleranzeige({ error, reset }: Props) { // TODO: allgemeine Meldung + Knopf, der reset aufruft return <div>???</div>; } export default function App() { const [versuche, setVersuche] = useState(0); const fehler = Object.assign(new Error("DB_CONN_REFUSED bei 10.0.0.7"), { digest: "a1b2c3", }); return ( <div style={{ fontFamily: "system-ui", padding: 16 }}> <p data-testid="versuche">Versuche: {versuche}</p> <Fehleranzeige error={fehler} reset={() => setVersuche((v) => v + 1)} /> </div> ); }