This tutorial focuses on the meaning and implementation of Resume Next
, GoTo 0
, and GoTo -1
. These critical components add structure to the VBA On Error
statement and any explicit handlers using GoTo [label]
.
In brief, Resume Next
goes to the next executable line, GoTo 0
turns off the currently enabled error handler, and GoTo -1
turns off the current exception. Of course, these things need a bit more explanation, otherwise we wouldn’t have written an entire tutorial about them!
Basic Error Handling Overview
For a more thorough exploration of basic error handling techniques, read our article dedicated to the On Error GoTo statement.
Error handling in VBA is disabled by default, so it must be turned on with the On Error
statement. If you want to explicitly handle errors, label a section of code and direct the execution flow to that section:
On Error GoTo fixErrors
'some code that might trigger an error
'On Error GoTo 0 'uncomment to disable fixErrors and enclose the section
Exit Sub
fixErrors:
'code to fix the error
'Resume Next 'uncomment this to return to original code
End Sub
The first line in the snippet turns on (enables) the
To shut off (disable) the active handler, use On Error GoTo 0
. Doing so will close off the code block that uses that handler. Alternatively, exit the subroutine using Exit Sub
, which automatically turns off the handler.
Calling another subroutine does not exit the current subroutine so any active handlers will be stacked in the new subroutine!
Error handling code must be placed before the End Sub
statement, so in order to avoid it running with the regular code, it should come after an Exit Sub
statement.
It’s wise to check inputs for the correct data types, formatting, and common issues like a divisor of zero. This reduces the prevalence of runtime errors before they can even arise.
How to Use Resume Next
Resume Next
plays a dual role:
- as a stand-in for a custom error handler that is marked by a label
- to return execution flow to the main body of the code after a custom handler completes
We’re going to talk about each of these roles in the next two sections.
Defer Handling
You can defer handling errors by using On Error Resume Next
, like in this snippet:
On Error GoTo fixErrors 'turns on fixErrors handler
On Error Resume Next 'Defers error handling
'code that might error
If you replace GoTo [label]
with Resume Next
, you can defer error handling. If an error is raised, execution simply skips that line of code and goes to the next one. If the next line raises an error, execution just skips that line, too. This definitely has some benefits, and we use it quite a lot on this site, like when checking if a file exists, but you need to be careful when applying it. If used to ignore a specific deficiency you know exists, you could mistakenly skip over an entire section of code without realizing it.
Using Resume Next
to defer handling has its purposes, such as eventually running code that forcibly rectifies the offending variables and objects. But I’d strongly recommend either explicitly handling errors with GoTo [label]
or avoiding errors by checking inputs with IF statements, where appropriate.
The main problem with the “ignore the errors” method is that users will not notice that the code is broken. It will run as long as deferment is active. However, some expected result will simply be incorrect or not be displayed at all. This leads to frustrated users trying to figure out what they did wrong when it was really a runtime problem with your code. Even worse, they may just accept the erroneous output, no matter how outlandish.
Resume Next
to defer errors has its place, but use it wisely. A good habit is to warn others (including your future self) that you’re using it. Clearly state this in the comments at the top module and describe why you’re doing it. This habit at least makes others aware that unnoticed errors may be lurking in the code.
Return Execution to the Main Block
Resume Next
is not, however, without a positive side. The same statement can return control to the main code block after entering a custom handler. This means you don’t have to end a subroutine every time a custom handler is employed.
On Error GoTo fixErrors
students_per_class = num_students / num_rooms
MsgBox ("You'll have " & students_per_class & " students per class")
On Error GoTo 0
Exit Sub
fixErrors:
If num_rooms = 0 Then
num_rooms = InputBox("Re-enter number of rooms")
students_per_class = num_students / num_rooms
End If
Resume Next
This code snippet predicts that a divide by zero error may be triggered and fixes it with some user interaction. Once the input is received and the new result calculated, the Resume Next
statement returns execution to the line immediately following the line that triggered the error.
If you’d like to return to the same line that triggered the error, you can simply use Resume
, like this:
On Error GoTo fixErrors
students_per_class = num_students / num_rooms
MsgBox ("You'll have " & students_per_class & " students per class")
On Error GoTo 0
Exit Sub
fixErrors:
If num_rooms = 0 Then
num_rooms = InputBox("Re-enter number of rooms")
End If
Resume
Using Resume
instead of Resume Next
has the added benefit of naturally looping until the user inputs a valid divisor for
Hidden Role
Resume
and Resume Next
actually play a third role when in the error handling block: once executed, they reset the current exception to Nothing
, meaning the active error handler can be used again.
Think of the error handler as a single-use tool, which must be reset before it can be used again. We know that ending and exiting the subroutine resets the handler. What this hidden role means is that Resume
and Resume Next
also resets the error handler.
Using GoTo 0
and GoTo -1
With VBA, only one error handler can be active at a time. This makes sense, as an error will immediately trigger the active handler, and VBA cannot guess between multiple handlers. To VBA, an error is an error is an error. You can distinguish errors using the Err
object and a Select Case
statement, but that’s for our next tutorial.
Make powerful macros with our free VBA Developer Kit It’s easy to copy and paste a macro like this, but it’s harder make one on your own. To help you make macros like this, we built a free VBA Developer Kit and wrote the Big Book of Excel VBA Macros full of hundreds of pre-built macros to help you master file I/O, arrays, strings and more - grab your free copy below.
Enable and Disable Handlers
Use On Error GoTo 0
to completely turn off error handling in a subroutine. This effectively resets the error handling in that sub to the default, which is no handling at all. You may decide to do this when you only have one handler, like
Note that you do not need to disable a handler before enabling another. The new one simply takes over. However, for clarity, I like to turn off a handler when its section of code ends. In this code snippet, it’s very clear which handlers go with which parts of the code.
On Error GoTo colorPicker
Range("A1:A30").Font.Color = colorChoice1
Range("B1:B30").Font.Color = colorChoice2
On Error GoTo 0
On Error GoTo fixErrors
students_per_class = num_students / num_rooms
MsgBox ("You'll have " & students_per_class & " students per class")
On Error GoTo 0
Clearing Exceptions
A particular error instance is called an exception. In the following code, there is one type of error but two exceptions, because each instance of the error throws an exception:
Range("A1:A30").Text.Color = vbRed
Range("B1:B30").Text.Color = vbBlue
'Range("B1:B30").Font.Color = vbBlue 'this is the correct object property
When the first error is raised, VBA directs flow immediately to the active error handler.
The single error handler rule applies even in the error code! Once an error has been raised, the error handler is completely “full”. In order to handle another error, the handler must be emptied first. Normally this is done by exiting the handler with End Sub
or Resume Next
. However, there is another method, which uses On Error GoTo -1
.
Let’s return to our divide by zero handler
fixErrors:
If num_rooms = 0 Then
num_rooms = InputBox("Re-enter number of rooms")
students_per_class = num_students / num_rooms
End If
Resume Next
But what happens if the user inputs zero again? The full error handler cannot take another exception and leads to a fatal error, killing the program.
You can reset the handler - that is, remove the current exception - by using On Error GoTo -1
:
fixErrors:
On Error GoTo -1 'clears triggering divide by zero error
If num_rooms = 0 Then
num_rooms = InputBox("Re-enter number of rooms")
students_per_class = num_students / num_rooms
End If
Resume Next
However, there is a flaw here! The GoTo -1
clears the current exception, and the Resume Next
statement sets off an infinite loop. Execution does NOT return to the original code section.
Since using GoTo -1
can be extremely confusing, I’d recommend not using it at all. If you are adamant about GoTo -1
, use it as a last resort and finish the error handling code with End Sub
.
Now you can use On Error GoTo 0
and Resume
or Resume Next
effectively. Unless absolutely necessary, I’d recommend steering clear of On Error GoTo -1
, as it can greatly complicate the logic of your program. I’d also recommend judiciously employing On Error Resume Next
deferment, because it can mean segments of your code just don’t do anything at all.