Solange alles glattläuft, brauchst du keine Fehlerbehandlung. Aber die Datei fehlt,
das Feld ist Null, die Division geht durch null, der Benutzer bricht ab — und
plötzlich steht dein Code mit einer hässlichen Fehlermeldung mitten im Ablauf. In
dieser Lektion baust du Prozeduren, die solche Situationen kontrolliert abfangen,
protokollieren und danach sauber weiterlaufen.
Warum überhaupt abfangen?
Ohne Fehlerbehandlung stoppt VBA bei einem Laufzeitfehler die Ausführung und zeigt einen Dialog. Für den Entwickler ist das beim Testen okay. Für den Anwender in einer fertigen Datenbank ist es ein Problem: offene Recordsets bleiben hängen, halbfertige Transaktionen sind unklar, und der Anwender liest eine Meldung, mit der er nichts anfangen kann.
Die Steueranweisung dafür heißt On Error. Sie gibt es in drei Varianten.
On Error GoTo — der Standard
On Error GoTo Label springt bei jedem Fehler ab dieser Zeile zu einer Sprungmarke.
Dort kümmerst du dich um das Problem. Das bewährte Muster sieht so aus:
Public Sub KundenExport()
On Error GoTo Fehler
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT * FROM tblKunden", dbOpenSnapshot)
Do Until rs.EOF
Debug.Print rs!Nachname
rs.MoveNext
Loop
Aufraeumen:
' Wird IMMER durchlaufen — im Erfolgs- wie im Fehlerfall
If Not rs Is Nothing Then
If rs.State = 1 Then rs.Close ' 1 = dbOpen / geöffnet
Set rs = Nothing
End If
Set db = Nothing
Exit Sub
Fehler:
MsgBox "Fehler " & Err.Number & ": " & Err.Description, _
vbCritical, "KundenExport"
Resume Aufraeumen
End Sub
Drei Bausteine machen dieses Muster aus:
Exit Subvor dem Fehler-Label. Ohne diese Zeile würde der normale Ablauf einfach in den Fehlerblock „hineinlaufen", obwohl gar kein Fehler auftrat.- Ein Aufräum-Label, das Recordset und Datenbank schließt — egal ob erfolgreich oder nach einem Fehler.
Resume Aufraeumenim Fehlerblock, damit auch im Fehlerfall aufgeräumt wird.
Wichtig: Ein
DAO.Recordsetimmer mitrs.Closeschließen und aufNothingsetzen. Vergisst du das im Fehlerfall, bleiben Sperren und Speicher hängen — bei Schleifen über viele Datensätze wird das schnell zum Problem.
Die Resume-Varianten
Im Fehlerblock entscheidest du mit Resume, wie es weitergeht:
| Anweisung | Wirkung |
|---|---|
Resume | Wiederholt die Zeile, die den Fehler ausgelöst hat. |
Resume Next | Macht mit der nächsten Zeile nach dem Fehler weiter. |
Resume Label | Springt zu einer benannten Marke (z. B. zum Aufräumen). |
Exit Sub / Exit Function | Verlässt die Prozedur direkt. |
On Error Resume Next — gezielt, nicht faul
On Error Resume Next ignoriert einen Fehler und macht mit der nächsten Zeile
weiter. Das ist kein Freibrief, sondern nur für eng begrenzte Stellen gedacht,
an denen du den Fehler direkt danach selbst prüfst:
Public Function TabelleExistiert(ByVal name As String) As Boolean
Dim def As DAO.TableDef
On Error Resume Next
Set def = CurrentDb.TableDefs(name) ' wirft Fehler, wenn nicht vorhanden
TabelleExistiert = (Err.Number = 0)
On Error GoTo 0 ' Fehlerbehandlung wieder abschalten
End Function
On Error GoTo 0 schaltet die Behandlung wieder aus, damit nachfolgende Fehler nicht
stillschweigend verschluckt werden.
Warnung: Ein globales
On Error Resume Nextüber eine ganze Prozedur versteckt echte Fehler und macht die Suche zur Qual. Setz es eng, prüfErr.Numbersofort, schalt es gleich wieder ab.
Das Err-Objekt auswerten
Nach einem Fehler stehen die Details im globalen Err-Objekt:
| Eigenschaft | Inhalt |
|---|---|
Err.Number | Die Fehlernummer (0 = kein Fehler). |
Err.Description | Der Klartext zur Nummer. |
Err.Source | Die Quelle (Projekt- oder Objektname). |
Mit Err.Clear setzt du das Objekt zurück. Es wird außerdem automatisch geleert,
sobald ein Resume, Exit oder ein neues On Error läuft.
Eigene Fehler auslösen: Err.Raise
Manchmal willst du selbst einen Fehler werfen, etwa wenn eine Vorbedingung verletzt
ist. Dafür gibt es Err.Raise. Für eigene Nummern benutzt du den Bereich ab
vbObjectError + 512, um Kollisionen mit Access-Fehlern zu vermeiden:
Public Sub RechnungBuchen(ByVal betrag As Currency)
If betrag <= 0 Then
Err.Raise vbObjectError + 513, "RechnungBuchen", _
"Der Betrag muss größer als 0 sein."
End If
' ... eigentliche Buchung ...
End Sub
Dieser Fehler landet dann in der aufrufenden Prozedur genauso im Err-Objekt wie
ein eingebauter Fehler.
Typische Access-Fehlernummern
Ein paar Nummern begegnen dir im Access-Alltag immer wieder:
| Nummer | Bedeutung |
|---|---|
| 6 | Überlauf (Wert passt nicht in den Datentyp). |
| 11 | Division durch null. |
| 13 | Typen unverträglich (Type mismatch), oft durch Null. |
| 91 | Objektvariable nicht gesetzt (Set vergessen). |
| 94 | Unzulässige Verwendung von Null. |
| 3021 | Kein aktueller Datensatz (BOF/EOF, Recordset leer). |
| 3061 | Zu wenige Parameter — meist eine offene Referenz in der Abfrage. |
| 3078 | Access findet die Tabelle oder Abfrage nicht. |
| 2501 | Eine DoCmd-Aktion wurde abgebrochen (z. B. OpenForm). |
| 2450 | Access findet das referenzierte Formular nicht. |
Zentrale Fehlerbehandlung und Logging
In größeren Projekten willst du Fehler nicht in jeder Prozedur einzeln vertexten,
sondern zentral protokollieren. Eine kleine Hilfsprozedur schreibt jeden Fehler in
eine Log-Tabelle tblFehlerLog mit den Feldern Zeitpunkt, Quelle, Nummer,
Beschreibung:
Public Sub FehlerLoggen(ByVal quelle As String, _
ByVal nummer As Long, _
ByVal beschreibung As String)
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("tblFehlerLog", dbOpenDynaset, dbAppendOnly)
rs.AddNew
rs!Zeitpunkt = Now
rs!Quelle = quelle
rs!Nummer = nummer
rs!Beschreibung = Left$(beschreibung, 255)
rs.Update
rs.Close
Set rs = Nothing
End Sub
Der Fehlerblock jeder Prozedur ruft dann nur noch diese eine Stelle auf:
Fehler:
FehlerLoggen "KundenExport", Err.Number, Err.Description
MsgBox "Beim Export ist ein Fehler aufgetreten. " & _
"Der Vorfall wurde protokolliert.", vbExclamation
Resume Aufraeumen
So sieht der Anwender eine verständliche Meldung, und du hast im Log alle Details für die spätere Analyse.
Zusammengefasst
On Error GoTo Labelist der Standard; kombiniere ihn mitExit Sub, einem Aufräum-Label undResume.On Error Resume Nextnur eng begrenzt einsetzen undErr.Numbersofort prüfen, dann mitOn Error GoTo 0abschalten.- Das
Err-Objekt liefertNumber,DescriptionundSource; mitErr.Raisewirfst du eigene Fehler. - Recordset und Datenbank immer im Aufräum-Label schließen, damit im Fehlerfall nichts hängen bleibt.
- Eine zentrale Log-Prozedur hält die Fehlerblöcke schlank und liefert dir eine auswertbare Historie.