Aikido

Behandlung von Fehlern in Catch-Blöcken: Warum leere Catch-Blöcke Produktionssysteme zerstören

Lesbarkeit

Regel
Umgang mit Fehler in auffangen Blöcken. 
Leere catch Blöcke geräuschlos schlucken Fehler, 
macht Fehlersuche erschwert. 
Unterstützte Sprachen: Java, C, C++, PHP, JavaScript, 
TypeScript, Go, Python

Einführung

Leere Catch-Blöcke sind eines der gefährlichsten Anti-Patterns im Produktionscode. Wenn Ausnahmen abgefangen, aber nicht behandelt werden, verschwindet der Fehler ohne eine Spur. Die Anwendung läuft mit beschädigten Zuständen, ungültigen Daten oder fehlgeschlagenen Operationen weiter, die die Ausführung hätten stoppen müssen. Die Benutzer sehen stille Fehler, bei denen Funktionen nicht funktionieren, erhalten aber keine Fehlermeldungen. Die Betriebsteams haben keine Protokolle zur Fehlersuche. Der einzige Hinweis darauf, dass etwas nicht in Ordnung ist, kommt Stunden oder Tage später, wenn kaskadenartige Ausfälle das System unbrauchbar machen.

Warum das wichtig ist

Fehlersuche und Fehlerbehebung: Leere Catch-Blöcke eliminieren Fehlerprotokolle. Ingenieure haben keine Stapelverfolgung, keine Fehlermeldung und keinen Hinweis darauf, wann oder wo der Fehler aufgetreten ist, was es nahezu unmöglich macht, Probleme zu reproduzieren.

Stille Datenbeschädigung: Wenn Datenbankoperationen oder API-Aufrufe innerhalb leerer Catch-Blöcke fehlschlagen, fährt die Anwendung fort, als wären sie erfolgreich gewesen. Datensätze werden teilweise aktualisiert, Transaktionen sind unvollständig, und wenn die Beschädigung entdeckt wird, ist der Prüfpfad verschwunden.

Sicherheitsschwachstellen: Leere Catch-Blöcke verdecken Sicherheitsfehler wie Authentifizierungsfehler oder Autorisierungsprüfungen. Ein Angreifer, der eine Ausnahme in einem sicherheitskritischen Pfad auslöst, könnte die Schutzmaßnahmen vollständig umgehen, wenn der Fehler stillschweigend verschluckt wird.

Kaskadierende Ausfälle: Wenn Fehler verschluckt werden, läuft die Anwendung in einem ungültigen Zustand weiter. Nachfolgende Vorgänge, die vom Ergebnis des fehlgeschlagenen Vorgangs abhängen, schlagen ebenfalls fehl, wodurch eine Kette von Fehlern entsteht, die die Ingenieure von der eigentlichen Ursache ablenkt.

Code-Beispiele

❌ Nicht konform:

async function updateUserProfile(userId, profileData) {
    try {
        await db.users.update(userId, profileData);
        await cache.invalidate(`user:${userId}`);
        await searchIndex.update(userId, profileData);
    } catch (error) {
        // TODO: handle error
    }

    return { success: true };
}

Warum es falsch ist: Wenn ein Vorgang fehlschlägt, wird der Fehler stillschweigend ignoriert und die Funktion gibt den Erfolg zurück. Die Datenbank könnte aktualisiert werden, aber die Cache-Invalidierung könnte fehlschlagen, so dass die Daten veraltet sind. Oder die Aktualisierung des Suchindex schlägt fehl, so dass der Benutzer nicht mehr gesucht werden kann, ohne dass ein Protokoll oder eine Warnung auf das Problem hinweist.

✅ Konform:

async function updateUserProfile(userId, profileData) {
    try {
        await db.users.update(userId, profileData);
        await cache.invalidate(`user:${userId}`);
        await searchIndex.update(userId, profileData);
        return { success: true };
    } catch (error) {
        logger.error('Failed to update user profile', {
            userId,
            error: error.message,
            stack: error.stack
        });
        throw new ProfileUpdateError(
            'Unable to update profile',
            { cause: error }
        );
    }
}

Warum das wichtig ist: Jeder Fehler wird mit dem Kontext protokolliert und liefert Informationen zur Fehlersuche. Der Fehler wird an den Aufrufer weitergegeben und ermöglicht eine angemessene Fehlerbehandlung auf der entsprechenden Ebene. Überwachungssysteme können auf diese Fehler aufmerksam machen, und die Anwendung schlägt schnell fehl, anstatt mit einem ungültigen Zustand fortzufahren.

Schlussfolgerung

Leere Catch-Blöcke sind im Produktionscode niemals akzeptabel. Jede abgefangene Ausnahme muss mindestens protokolliert werden, und die meisten müssen an den Aufrufer weitergegeben werden oder spezifische Wiederherstellungsmaßnahmen auslösen. Wenn Sie einen Fehler wirklich ignorieren müssen, dokumentieren Sie den Grund dafür mit einem Kommentar, der die geschäftliche Rechtfertigung erläutert. Die Vorgabe sollte immer sein, Fehler explizit zu behandeln und sie nicht stillschweigend zu verwerfen.

FAQs

Haben Sie Fragen?

Was ist, wenn ich bestimmte Fehler wirklich ignorieren muss?

Dokumentieren Sie ihn ausdrücklich mit einem Kommentar, der erklärt, warum der Fehler sicher ignoriert werden kann. Protokollieren Sie den Fehler auf Debug-Ebene, damit er in ausführlichen Protokollen erscheint, aber keine Warnungen auslöst. Überlegen Sie, ob das Ignorieren des Fehlers zu einem ungültigen Zustand führen könnte. Selbst bei "erwarteten" Fehlern wie Cache-Fehlern oder Netzwerk-Timeouts hilft die Protokollierung den Betriebsteams, Muster im Systemverhalten zu verstehen.

Sollte ich Fehler immer in Catch-Blöcken protokollieren?

Die Protokollierung ist in der Regel eine gute Idee, da man Probleme nicht beheben kann, ohne zu sehen, was fehlgeschlagen ist. Es gibt Fälle, in denen man das Problem auch ohne Protokollierung nachvollziehen kann, z. B. wenn der Fehler sofort zurückgeworfen wird, um an anderer Stelle behandelt zu werden, oder wenn die Anwendung bei kritischen Fehlern abstürzen und neu gestartet werden muss. Aber eine ordentliche Protokollierung ist immer hilfreich.

Was ist der Unterschied zwischen der Protokollierung und dem erneuten Auftreten von Fehlern?

Bei der Protokollierung werden die Ereignisse zur Fehlersuche und Überwachung aufgezeichnet. Das erneute Auslösen gibt den Fehler an den Aufrufer weiter, damit dieser entscheiden kann, wie er reagieren soll. Machen Sie beides: protokollieren Sie den Fehler mit dem Kontext an der Fehlerstelle und werfen Sie ihn dann erneut aus (möglicherweise in einem spezifischeren Fehlertyp), damit der Aufrufer die Wiederherstellung übernehmen kann. Protokollieren Sie nicht denselben Fehler auf mehreren Ebenen, das erzeugt Rauschen.

Wie behandle ich Fehler, die in finally-Blöcken auftreten?

Abschließende Blöcke sollten nur selten Fehler auslösen. Wenn sie fehleranfällige Operationen durchführen müssen (wie das Schließen von Ressourcen), verpacken Sie diese in ein eigenes try-catch. Protokollieren Sie alle Fehler, aber lassen Sie sie nicht den ursprünglichen Fehler maskieren. Einige Sprachen bieten eine Syntax für die Behandlung von Hauptfehlern und Finally-Block-Fehlern; verwenden Sie diese Mechanismen, um beide Fehlerkontexte zu erhalten.

Was ist mit den Auswirkungen auf die Leistung, wenn jeder Fehler protokolliert wird?

Die Protokollierung ist billig, verglichen mit den Kosten für die Fehlersuche bei Produktionsproblemen ohne Protokolle. Moderne Logging-Frameworks sind hoch optimiert. Wenn Sie so viele Fehler haben, dass die Protokollierung die Leistung beeinträchtigt, sollten Sie die Fehler beheben, anstatt sie zu verstecken. Hohe Fehlerraten deuten auf ernsthafte Probleme hin, die durch leere Catch-Blöcke nur noch schlimmer werden.

Sollten catch-Blöcke immer Fehler auslösen, oder können sie Fehlerwerte zurückgeben?

Das hängt von der Sprache und der Architektur ab. In JavaScript mit Versprechen wird ein Wurf aus catch an den nächsten Error-Handler weitergegeben. Die Rückgabe eines Fehlerobjekts aus catch löst das Versprechen mit diesem Fehler auf, was normalerweise falsch ist. Machen Sie sich mit der Semantik der Fehlerbehandlung in Ihrer Sprache vertraut. Im Allgemeinen lassen Sie Fehler weiterlaufen, es sei denn, Sie können sie sinnvoll beheben.

Wie behandle ich Fehler in asynchronen Operationen, die nicht über try-catch verfügen?

Verwenden Sie .catch()-Handler für Versprechen, Fehler-Ereignis-Listener für Ereignis-Emittenten oder Fehler-Callbacks in Callback-basierten APIs. Ignorieren Sie niemals Ablehnungshandler oder Fehlerrückrufe. Unbehandelte Ablehnungen von Versprechen sollten auf Prozessebene überwacht und als kritische Fehler behandelt werden. Modernes Node.js kann sich bei unbehandelten Ablehnungen beenden, was besser ist als ein stilles Scheitern.

Starten Sie kostenlos

Sichern Sie Ihren Code, Cloud und die Laufzeit in einem zentralen System.
Finden und beheben Sie Schwachstellen schnell  automatisch.

Keine Kreditkarte erforderlich | Scanergebnisse in 32 Sekunden.