After months of insecurity/confusion about some obscure laws of VBA error handling, never fully satisfied by any of the popular documentation pages (Microsoft VBA/VB, C. Pearson and a others), I dedicated some days of trial and error to reconstruct the
complete set of the (written and unwritten/corrected) rules governing VBA error handling:
LEGEND:
1A: On Error Goto 0. 1B: On Error GoTo line/label. 1C: On Error Resume Next
2A: an error occurs. 2B: On Error GoTo -1
3: being in a subprocedure, temporarily, just until coming back
4: Erl
5: Resume […]
6: Exit […], End […]
RULES:
- With 1A in effect*, error handling is and stays disabled and inactive. This is the default.
- With 1B in effect*, error handling is initially disabled and inactive; it's activated on 2A and inactivated while 3 and by 5 or 6, and it's disabled while 3 and by 2A or 6.
- With 1C in effect*, error handling is initially disabled and inactive; it stays inactive (supposedly activated and inactivated immediately on 2A), and it's disabled while 3 and by 6.
- *= If 1A, 1B, 1C are called while error handling is active, the Err object is cleared immediately but the On Error action change effect is delayed until error handling is inactivated (by 5 or 6).
- 2B (instantaneously) reverses the effect of 2A: error handling is inactivated and returns(1B)/stays(1C) enabled.
- 1A, 1B, 1C, 2B, 5, 6 also instantaneously clears the Err object.
- If an error occurs while in a subprocedure, if unhandled (disabled) in the current subprocedure it's passed to the first calling (parent) procedure where it's enabled and inactive. If no one is found, it stays there (in the subproc.).
- 4 if error handling is active returns the line (if specified as a number label) of last error, otherwise 0.
- 5 (correctly) crashes (err 21: "Resume without error") if called while error handling is inactive.
With all these rules fresh in mind, and starting from the D_Bester's solution posted here, here's my revised solution correcting a couple of errors/inefficiences in his code:
Sub InLineErrorHandling()
'code without error handling
On Error GoTo ErrHandler1 'enable error handler
'code block that may result in an error
Dim a As String: a = "Abc"
Dim c As Integer: c = a 'type mismatch
'inline error handler routine
ErrHandler1:
If Err.Number <> 0 Then
Debug.Print err.Description
On Error GoTo -1 ' inactivate error handler
End If
On Error GoTo 0 'disable error handler
'more code without error handling (default mode)
Err.Raise 123
End Sub
...that if no errors are expected in the error handling routine, can be further reduced to this (very standard) alternative:
Sub InLineErrorHandling()
'code without error handling
On Error Resume Next 'enable error handler
'code block that may result in an error
Dim a As String: a = "Abc"
Dim c As Integer: c = a 'type mismatch
'inline error handler routine
If Err.Number <> 0 Then
Debug.Print err.Description
End If
On Error GoTo 0 'disable error handler
'more code without error handling (default mode)
err.Raise 123
End Sub
It also worth mentioning that, in both the choices, if we also want to know what line (first for 1B, last for 1C) of the "code block that may result in an error" resulted in an error, we can use the Erl function, like this:
...
'code block that may result in an error
10 Dim a As String: a = "Abc"
20 Dim c As Integer: c = a 'type mismatch
'inline error handler routine
If Err.Number <> 0 Then
Debug.Print "Error """ & err.Description & """ in line " & Err
...