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
Resumeversucht 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 Nextmacht hinter dem Fehlschlag weiter. Gut für „protokollieren und weiter", gefährlich, wenn die übersprungene Zeile tragend war.Resume Labelist das Arbeitspferd: Es schickt die Steuerung zu deinemSauberRaus:, 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
- VBA On Error — Resume Next vs. GoTo & warum Makros Bugs verstecken
- VBA Err-Objekt — Number, Description & eigene Fehler auslösen
- VBA Sub in Excel — Prozeduren, Aufruf & warum dein Makro nur ein Sub ist
- VBA For-Schleife in Excel — 8 Praxisbeispiele
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.
