🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Fehlerbehandlung in Excel — Das eine Muster, das jedes verlässliche Makro nutzt

|

VBA Fehlerbehandlung in Excel — Das eine Muster, das jedes verlässliche Makro nutzt

Getestet in: Excel 365 v2509 · Excel 2021 · Excel 2019 · zuletzt geprüft am 08.06.2026

Kurz gesagt — VBA hat kein try/catch. Verlässliche Fehlerbehandlung ist eine Form, die du in jeder Prozedur wiederverwendest, auf die es ankommt: oben eine Routine scharfschalten, die Arbeit erledigen, jeden Ausgang — Erfolg wie Fehlschlag — durch einen einzigen Aufräumpunkt leiten, dann verlassen. Kopier diese Vorlage:

Sub BerichtVerarbeiten()
    On Error GoTo Fehlerbehandlung
    Application.ScreenUpdating = False        ' Zustand, den wir später wiederherstellen MÜSSEN

    Dim ws As Worksheet
    Set ws = Sheets("Daten")                  ' jeder Fehler hier springt zu Fehlerbehandlung
    ws.Range("A1:A1000").Value = 0

SauberRaus:                                   ' der EINE Ausgang, durch den jeder Weg geht
    Application.ScreenUpdating = True         ' immer wiederhergestellt, Fehler oder nicht
    Exit Sub

Fehlerbehandlung:
    MsgBox "BerichtVerarbeiten fehlgeschlagen: " & Err.Description
    Resume SauberRaus                         ' aufräumen, dann gehen
End Sub

Diese Struktur — On Error GoTo / Arbeit / SauberRaus: / Exit Sub / Fehlerbehandlung: / Resume SauberRaus — ist die ganze Disziplin. Der Rest dieses Leitfadens erklärt das Warum jeder Zeile.

Das Denkmodell: Du baust das try/finally von Hand, das VBA dir nicht gibt

Sprachen wie Python und C# haben try / except / finally. VBA hat nichts davon. Stattdessen gibt es dir drei Bausteine — On Error GoTo Label, ein Label und Resume — und die Erwartung, dass du sie selbst zur entsprechenden Struktur zusammensetzt.

Bilde es auf try/finally ab, und es wirkt nicht länger willkürlich:

try/catch/finally VBA-Entsprechung
try { On Error GoTo Fehlerbehandlung
catch (e) { der Fehlerbehandlung:-Block, der Err liest
finally { der SauberRaus:-Block, den beide Wege erreichen
throw Err.Raise

Sobald du die Vorlage als „try/finally von Hand" siehst, wird die Platzierung jeder Zeile offensichtlich statt auswendig gelernt. Der nicht verhandelbare Teil ist das einzige Aufräum-Label, das sowohl der Erfolgs- als auch der Fehlerweg durchläuft.

Die eine Regel: Resume entscheidet, wohin du nach der Routine gehst — falsch gewählt und du läufst im Kreis oder verlierst Ressourcen

In einer Routine hast du drei Wege, fortzufahren, und der falsche zu wählen ist der klassische VBA-Fehlerbehandlungs-Bug:

Resume              ' die genau gescheiterte Zeile ERNEUT ausführen — nur sicher, wenn du die Ursache behoben hast
Resume Next         ' die gescheiterte Zeile ÜBERSPRINGEN, mit der danach weitermachen
Resume SauberRaus   ' zu einem Label SPRINGEN — normalerweise dein einziger Aufräum-Ausgang
  • Resume versucht die schuldige Zeile erneut. Nimm es nur, wenn die Routine etwas geändert hat, damit der erneute Versuch gelingen kann (einen fehlenden Ordner angelegt, eine geschlossene Mappe geöffnet). Blind eingesetzt, bekommst du eine Endlosschleife — scheitern, behandeln, erneut versuchen, scheitern, für immer.
  • Resume Next macht hinter dem Fehlschlag weiter. Gut für „protokollieren und weiter", gefährlich, wenn die übersprungene Zeile tragend war.
  • Resume Label ist das Arbeitspferd: Es schickt die Steuerung zu deinem SauberRaus:, damit das Aufräumen immer läuft, bevor die Prozedur endet.

Eine Routine, die einfach ohne Resume/Exit ans Ende fällt, lässt den Fehler das Makro faktisch stoppen — entscheide den Ausgang also stets ausdrücklich.

Der Teil, den alle überspringen: der einzige Aufräumpunkt ist es, der deine Datei rettet

Hier ist die Fehlerart, die aus einem kleinen Bug ein Support-Ticket macht. Ein Makro setzt für Tempo einen globalen Excel-Zustand:

Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

… und scheitert dann bevor es sie wieder anschaltet. Jetzt ist Excel eingefroren und rechnet nicht mehr neu, und der Anwender denkt, Excel selbst sei kaputt — lange nachdem dein Makro beendet war. Dieselbe Geschichte gilt für ein offenes Datei-Handle (bleibt gesperrt), ein Set-Objekt (nie freigegeben) oder ein ungeschützt gelassenes Blatt.

Die Lösung ist strukturell, nicht sorgfältiges Tippen: Setz jede „muss immer laufen"-Zeile an ein einziges Label, das sowohl der normale Weg als auch die Routine erreicht, und lass die Routine dorthin Resumen:

Sub DateiImportieren()
    Dim ff As Integer
    On Error GoTo Fehlerbehandlung
    Application.ScreenUpdating = False
    ff = FreeFile
    Open "C:\Daten\eingang.csv" For Input As #ff
    ' ... die Datei lesen, was auf halbem Weg platzen könnte ...

SauberRaus:
    If ff <> 0 Then Close #ff             ' Datei IMMER geschlossen
    Application.ScreenUpdating = True      ' Oberfläche IMMER wiederhergestellt
    Exit Sub
Fehlerbehandlung:
    MsgBox "Import fehlgeschlagen: " & Err.Description
    Resume SauberRaus                     ' der Fehlerweg geht auch durchs Aufräumen
End Sub

Der Erfolg fällt in SauberRaus. Der Fehlschlag springt zu Fehlerbehandlung, dann Resume SauberRaus. Beide Routen schließen die Datei und stellen die Oberfläche wieder her. Das ist dein finally.

Fehler an den Aufrufer hochreichen (Re-Raise)

Ein tief liegender Helfer sollte meist nicht entscheiden, wie die ganze Anwendung reagiert — er sollte seine eigenen Ressourcen aufräumen und den Aufrufer entscheiden lassen. Fang den Fehler ab, stell den Zustand wieder her, dann löse ihn erneut aus:

Private Sub DatenLaden()
    On Error GoTo Fehlerbehandlung
    ' ... Arbeit, die scheitern kann ...
    Exit Sub
Fehlerbehandlung:
    Dim n As Long, d As String, s As String
    n = Err.Number: d = Err.Description: s = Err.Source   ' sichern, bevor das Aufräumen Err löscht
    ' (lokales Aufräumen hier)
    Err.Raise n, s, d                                     ' erneut zur Routine des Aufrufers werfen
End Sub

Sichere die Err-Werte zuerst — Aufräum-Anweisungen löschen Err unter deinen Händen. Dann schickt Err.Raise den ursprünglichen Fehler hoch zu wem auch immer DatenLaden aufrief, wo eine Routine auf oberster Ebene ihn einmal protokollieren und dem Anwender eine saubere Meldung zeigen kann.

Eine zentrale Protokoll-Routine

Für alles, was du auslieferst, protokolliere Fehler irgendwo, wo du sie später lesen kannst, statt darauf zu vertrauen, dass der Anwender eine MsgBox abfotografiert:

Fehlerbehandlung:
    FehlerProtokollieren "BerichtVerarbeiten", Err.Number, Err.Description
    Resume SauberRaus
End Sub

Private Sub FehlerProtokollieren(proz As String, num As Long, beschr As String)
    Dim ff As Integer: ff = FreeFile
    Open ThisWorkbook.Path & "\fehler_log.txt" For Append As #ff
    Print #ff, Now & " | " & proz & " | " & num & " | " & beschr
    Close #ff
End Sub

Wann On Error Resume Next das richtige Werkzeug ist

Nicht jede Lage will eine Routine. Für eine einzige Zeile, bei der Scheitern erwartet und harmlos ist — etwa zu prüfen, ob ein Objekt existiert —, ist enges Resume Next sauberer als ein Label, solange du Err.Number prüfst und mit On Error GoTo 0 entschärfst:

On Error Resume Next
Set ws = Sheets("Optional")
On Error GoTo 0
If ws Is Nothing Then Set ws = Sheets.Add   ' existierte nicht → anlegen

Die ganze Aufstellung, wann das sicher ist und wann leichtsinnig, steht in On Error: Resume Next vs. GoTo.

Die Meinung: Reife misst sich nicht an der Zahl der Routinen — sondern daran, ob sie zusammenlaufen

Du kannst On Error GoTo über jede Prozedur streuen und trotzdem fragile Makros schreiben. Das Signal für Reife in der Fehlerbehandlung ist enger und härter: Hat jede Prozedur einen Ausgang, den alle Wege durchlaufen, an dem das Aufräumen passiert? Lautet die Antwort nein, dann lässt ein einziger Fehler mitten in der Prozedur ScreenUpdating aus, die Rechen-Engine manuell und eine Datei gesperrt — und dein Anwender gibt Excel die Schuld, nicht deinem Code.

Meine Latte für „dieses Makro ist produktionsreif" ist also nicht das Vorhandensein von Routinen. Sie lautet: Such dir irgendeine Zeile aus, stell dir vor, sie wirft einen Fehler — wird die Datei trotzdem geschlossen und die Oberfläche trotzdem wiederhergestellt? Wenn ja, hast du das Muster verinnerlicht. Wenn nein, retten dich mehr On Error-Anweisungen nicht; ein SauberRaus: schon.

Häufige Fehlerbehandlungs-Fehler (und die Lösung)

Symptom Ursache Lösung
Excel „friert ein" nach einem Makro-Fehler ScreenUpdating/Calculation nie wiederhergestellt an einem SauberRaus: wiederherstellen, zu dem die Routine Resumet
Datei bleibt gesperrt / „bereits offen" Close/Set …= Nothing auf dem Fehlerweg übersprungen Aufräumen an den einen Ausgang setzen, den beide Wege erreichen
Endlosschleife Resume versucht eine Zeile erneut, deren Ursache nicht behoben war Resume Next oder Resume Label nehmen, kein nacktes Resume
Aufrufer erfährt nie vom Fehlschlag Helfer verschluckte den Fehler mit einer MsgBox Err sichern, aufräumen, dann Err.Raise zum erneuten Werfen
Protokoll zeigt Fehler 0 Err gelesen, nachdem das Aufräumen es löschte Err.Number/Description vor dem Aufräumen kopieren
Erfolg zeigt auch die Fehlermeldung kein Exit Sub vor Fehlerbehandlung: Exit Sub (oder in SauberRaus fallen) vor das Label setzen

Wenn das Aufräumen die Arbeit überwiegt — beschreib die Aufgabe einfach

Schau zurück auf diese Vorlage. Die eigentliche Aufgabe sind zwei Zeilen; die Routine, das Aufräum-Label, das Resume, das Protokollieren, das Re-Raise sind die anderen zwanzig. Dieses Verhältnis wird auf echten Pipelines nur schlimmer. ExcelMaster Agent lässt dich die Aufgabe beschreiben — „importiere diese CSVs, gleiche über die Bestell-ID ab, markiere Abweichungen, maile die Buchhaltung" — in Klartext-Deutsch, und das erzeugte Python behandelt Fehlschläge, stellt den Zustand wieder her und sichert deine Arbeitsmappe, bevor es irgendetwas anfasst. Kein On Error, kein Resume, kein eingefrorenes Excel. Kostenlos testen →

Verwandte Anleitungen

FAQ

Hat VBA try/catch? Nein. VBA hat kein try/catch/finally. Du baust die Entsprechung aus On Error GoTo Label, einem Routine-Label, einem einzigen Aufräum-Label und Resume. Die Standard-Vorlage schaltet oben eine Routine scharf, leitet jeden Ausgang durch einen Aufräumpunkt und verlässt dann.

Was ist das beste Fehlerbehandlungs-Muster in VBA? Schalte On Error GoTo Fehlerbehandlung scharf, erledige die Arbeit, dann hab ein SauberRaus:-Label, an dem du den Zustand wiederherstellst (ScreenUpdating, offene Dateien, Objekte) und Exit Sub. Der Fehlerbehandlung:-Block liest Err, protokolliert ihn bei Bedarf und macht Resume SauberRaus. Sowohl Erfolg als auch Fehlschlag gehen durchs gleiche Aufräumen — das ist der Schlüssel.

Was ist der Unterschied zwischen Resume, Resume Next und Resume Label? Resume führt die gescheiterte Zeile erneut aus (nur sicher, wenn die Routine die Ursache behoben hat, sonst gibt es eine Endlosschleife). Resume Next überspringt die gescheiterte Zeile und macht weiter. Resume Label springt zu einem Label — meist deinem einzigen Aufräum-Ausgang, damit das Aufräumen immer läuft.

Wie stelle ich sicher, dass das Aufräumen nach einem Fehler in VBA immer läuft? Setz jede „muss immer laufen"-Anweisung an ein Label (z. B. SauberRaus:), platziert so, dass der normale Weg hineinfällt, und lass die Fehlerbehandlungsroutine Resume SauberRaus machen. Beide Wege führen dann das Aufräumen aus. Das ist VBAs Ersatz für einen finally-Block.

Wie reiche ich einen Fehler von einem Helfer an die aufrufende Prozedur weiter? Sichere in der Routine des Helfers Err.Number, Err.Description und Err.Source in Variablen, mach jegliches lokale Aufräumen, dann ruf Err.Raise mit diesen gesicherten Werten auf. Der Fehler pflanzt sich zur On Error-Routine des Aufrufers fort, wo du ihn einmal protokollieren und dem Anwender eine einzige Meldung zeigen kannst.