An error-handling subroutine will either:
Resume
keyword to resume execution inside the same procedure.The Resume
keyword should only ever be used inside an error handling subroutine, because if VBA encounters Resume
without being in an error state, runtime error 20 "Resume without error" is raised.
There are several ways an error-handling subroutine may use the Resume
keyword:
Resume
used alone, execution continues on the statement that caused the error. If the error isn't actually handled before doing that, then the same error will be raised again, and execution might enter an infinite loop.Resume Next
continues execution on the statement immediately following the statement that caused the error. If the error isn't actually handled before doing that, then execution is permitted to continue with potentially invalid data, which may result in logical errors and unexpected behavior.Resume [line label]
continues execution at the specified line label (or line number, if you're using legacy-style line numbers). This would typically allow executing some cleanup code before cleanly exiting the procedure, such as ensuring a database connection is closed before returning to the caller.The On Error
statement itself can use the Resume
keyword to instruct the VBA runtime to effectively ignore all errors.
If the error isn't actually handled before doing that, then execution is permitted to continue with potentially invalid data, which may result in logical errors and unexpected behavior.
The emphasis above cannot be emphasized enough. On Error Resume Next effectively ignores all errors and shoves them under the carpet. A program that blows up with a runtime error given invalid input is a better program than one that keeps running with unknown/unintended data - be it only because the bug is much more easily identifiable. On Error Resume Next
can easily hide bugs.
The On Error
statement is procedure-scoped - that's why there should normally be only one, single such On Error
statement in a given procedure.
However sometimes an error condition can't quite be avoided, and jumping to an error-handling subroutine only to Resume Next
just doesn't feel right. In this specific case, the known-to-possibly-fail statement can be wrapped between two On Error
statements:
On Error Resume Next
[possibly-failing statement]
Err.Clear 'resets current error
On Error GoTo 0
The On Error GoTo 0
instruction resets error handling in the current procedure, such that any further instruction causing a runtime error would be unhandled within that procedure and instead passed up the call stack until it is caught by an active error handler. If there is no active error handler in the call stack, it will be treated as an unhandled exception.
Public Sub Caller()
On Error GoTo Handler
Callee
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & " in Caller."
End Sub
Public Sub Callee()
On Error GoTo Handler
Err.Raise 1 'This will be handled by the Callee handler.
On Error GoTo 0 'After this statement, errors are passed up the stack.
Err.Raise 2 'This will be handled by the Caller handler.
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & " in Callee."
Resume Next
End Sub