I just want to ask: How can i implement «EXCEL» functions such as:
iferror
iserror
in VBA «WORD». I know how to do it in excel but not in word.
e.g. (excel)
application.worksheetfunction.iferror( ... )
but i am doing the code in MSWord. The above function doesn’t seem to work.
Q1. Is it possible?
Q2. If yes, can you enlighten me on the code pattern?
I tried searching for google answers but all seem to point on excel method. Thank you so much..
Edit:
To elaborate my problem, i have a userform in Word that should collect numerical value and store in variable
qty1, qty2 … qty18, then uc1, uc2 … uc18
so if I process the variables
If Me.qty1.Value * Me.uc1.Value <> 0 Then
tot1 = Me.qty1.Value * Me.uc1.Value
Else
tot1 = ""
End If
it gives me error:
type mismatch
because when i leave qty2 to qty18 empty, it is understood as null string (?) just like in excel.
Are there any other way to do this?
In this Article
- VBA Errors Cheat Sheet
- Errors
- VBA Error Handling
- VBA On Error Statement
- On Error GoTo 0
- On Error Resume Next
- Err.Number, Err.Clear, and Catching Errors
- On Error GoTo Line
- VBA IsError
- If Error VBA
- VBA Error Types
- Runtime Errors
- Syntax Errors
- Compile Errors
- Debug > Compile
- OverFlow Error
- Other VBA Error Terms
- VBA Catch Error
- VBA Ignore Error
- VBA Throw Error / Err.Raise
- VBA Error Trapping
- VBA Error Message
- VBA Error Handling in a Loop
- VBA Error Handling in Access
VBA Errors Cheat Sheet
Errors
On Error – Stop code and display error
On Error Goto 0
On Error – Skip error and continue running
On Error Resume Next
On Error – Go to a line of code [Label]
On Error Goto [Label]
Clears (Resets) Error
On Error GoTo –1
Show Error number
MsgBox Err.Number
Show Description of error
MsgBox Err.Description
Function to generate own error
Err.Raise
See more VBA “Cheat Sheets” and free PDF Downloads
VBA Error Handling
VBA Error Handling refers to the process of anticipating, detecting, and resolving VBA Runtime Errors. The VBA Error Handling process occurs when writing code, before any errors actually occur.
VBA Runtime Errors are errors that occur during code execution. Examples of runtime errors include:
- Referencing a non-existent workbook, worksheet, or other object (Run-time Error 1004)
- Invalid data ex. referencing an Excel cell containing an error (Type Mismatch – Run-time Error 13)
- Attempting to divide by zero
VBA On Error Statement
Most VBA error handling is done with the On Error Statement. The On Error statement tells VBA what to do if it encounters an error. There are three On Error Statements:
- On Error GoTo 0
- On Error Resume Next
- On Error GoTo Line
On Error GoTo 0
On Error GoTo 0 is VBA’s default setting. You can restore this default setting by adding the following line of code:
On Error GoTo 0
When an error occurs with On Error GoTo 0, VBA will stop executing code and display its standard error message box.
Often you will add an On Error GoTo 0 after adding On Error Resume Next error handling (next section):
Sub ErrorGoTo0()
On Error Resume Next
ActiveSheet.Shapes("Start_Button").Delete
On Error GoTo 0
'Run More Code
End Sub
On Error Resume Next
On Error Resume Next tells VBA to skip any lines of code containing errors and proceed to the next line.
On Error Resume Next
Note: On Error Resume Next does not fix an error, or otherwise resolve it. It simply tells VBA to proceed as if the line of code containing the error did not exist. Improper use of On Error Resume Next can result in unintended consequences.
A great time to use On Error Resume Next is when working with objects that may or may not exist. For example, you want to write some code that will delete a shape, but if you run the code when the shape is already deleted, VBA will throw an error. Instead you can use On Error Resume Next to tell VBA to delete the shape if it exists.
On Error Resume Next
ActiveSheet.Shapes("Start_Button").Delete
On Error GoTo 0
Notice we added On Error GoTo 0 after the line of code containing the potential error. This resets the error handling.
In the next section we’ll show you how to test if an error occurred using Err.Number, giving you more advanced error handling options.
VBA Coding Made Easy
Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
Learn More
Err.Number, Err.Clear, and Catching Errors
Instead of simply skipping over a line containing an error, we can catch the error by using On Error Resume Next and Err.Number.
Err.Number returns an error number corresponding with the type of error detected. If there is no error, Err.Number = 0.
For example, this procedure will return “11” because the error that occurs is Run-time error ’11’.
Sub ErrorNumber_ex()
On Error Resume Next
ActiveCell.Value = 2 / 0
MsgBox Err.Number
End Sub
Error Handling with Err.Number
The true power of Err.Number lies in the ability to detect if an error occurred (Err.Number <> 0). In the example below, we’ve created a function that will test if a sheet exists by using Err.Number.
Sub TestWS()
MsgBox DoesWSExist("test")
End Sub
Function DoesWSExist(wsName As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(wsName)
'If Error WS Does not exist
If Err.Number <> 0 Then
DoesWSExist = False
Else
DoesWSExist = True
End If
On Error GoTo -1
End Function
Note: We’ve added a On Error GoTo -1 to the end which resets Err.Number to 0 (see two sections down).
With On Error Resume Next and Err.Number, you can replicate the “Try” & “Catch” functionality of other programming languages.
On Error GoTo Line
On Error GoTo Line tells VBA to “go to” a labeled line of code when an error is encountered. You declare the Go To statement like this (where errHandler is the line label to go to):
On Error GoTo errHandler
and create a line label like this:
errHandler:
Note: This is the same label that you’d use with a regular VBA GoTo Statement.
Below we will demonstrate using On Error GoTo Line to Exit a procedure.
On Error Exit Sub
You can use On Error GoTo Line to exit a sub when an error occurs.
You can do this by placing the error handler line label at the end of your procedure:
Sub ErrGoToEnd()
On Error GoTo endProc
'Some Code
endProc:
End Sub
or by using the Exit Sub command:
Sub ErrGoToEnd()
On Error GoTo endProc
'Some Code
GoTo skipExit
endProc:
Exit Sub
skipExit:
'Some More Code
End Sub
Err.Clear, On Error GoTo -1, and Resetting Err.Number
After an error is handled, you should generally clear the error to prevent future issues with error handling.
After an error occurs, both Err.Clear and On Error GoTo -1 can be used to reset Err.Number to 0. But there is one very important difference: Err.Clear does not reset the actual error itself, it only resets the Err.Number.
What does that mean? Using Err.Clear, you will not be able to change the error handling setting. To see the difference, test out this code and replace On Error GoTo -1 with Err.Clear:
Sub ErrExamples()
On Error GoTo errHandler:
'"Application-defined" error
Error (13)
Exit Sub
errHandler:
' Clear Error
On Error GoTo -1
On Error GoTo errHandler2:
'"Type mismatch" error
Error (1034)
Exit Sub
errHandler2:
Debug.Print Err.Description
End Sub
Typically, I recommend always using On Error GoTo -1, unless you have a good reason to use Err.Clear instead.
VBA On Error MsgBox
You might also want to display a Message Box on error. This example will display different message boxes depending on where the error occurs:
Sub ErrorMessageEx()
Dim errMsg As String
On Error GoTo errHandler
'Stage 1
errMsg = "An error occured during the Copy & Paste stage."
'Err.Raise (11)
'Stage 2
errMsg = "An error occured during the Data Validation stage."
'Err.Raise (11)
'Stage 3
errMsg = "An error occured during the P&L-Building and Copy-Over stage."
Err.Raise (11)
'Stage 4
errMsg = "An error occured while attempting to log the Import on the Setup Page"
'Err.Raise (11)
GoTo endProc
errHandler:
MsgBox errMsg
endProc:
End Sub
Here you would replace Err.Raise(11) with your actual code.
VBA IsError
Another way to handle errors is to test for them with the VBA ISERROR Function. The ISERROR Function tests an expression for errors, returning TRUE or FALSE if an error occurs.
Sub IsErrorEx()
MsgBox IsError(Range("a7").Value)
End Sub
VBA Programming | Code Generator does work for you!
If Error VBA
You can also handle errors in VBA with the Excel IFERROR Function. The IFERROR Function must be accessed by using the WorksheetFunction Class:
Sub IfErrorEx()
Dim n As Long
n = WorksheetFunction.IfError(Range("a10").Value, 0)
MsgBox n
End Sub
This will output the value of Range A10, if the value is an error, it will output 0 instead.
VBA Error Types
Runtime Errors
As stated above:
VBA Runtime Errors are errors that occur during code execution. Examples of runtime errors include:
- Referencing a non-existent workbook, worksheet, or other object
- Invalid data ex. referencing an Excel cell containing an error
- Attempting to divide by zero
You can “error handle” runtime errors using the methods discussed above.
Syntax Errors
VBA Syntax Errors are errors with code writing. Examples of syntax errors include:
- Mispelling
- Missing or incorrect punctuation
The VBA Editor identifies many syntax errors with red highlighting:
The VBA Editor also has an option to “Auto Syntax Check”:
When this is checked, the VBA Editor will generate a message box alerting you syntax errors after you enter a line of code:
I personally find this extremely annoying and disable the feature.
Compile Errors
Before attempting to run a procedure, VBA will “compile” the procedure. Compiling transforms the program from source code (that you can see) into executable form (you can’t see).
VBA Compile Errors are errors that prevent the code from compiling.
A good example of a compile error is a missing variable declaration:
Other examples include:
- For without Next
- Select without End Select
- If without End If
- Calling a procedure that does not exist
Syntax Errors (previous section) are a subset of Compile Errors.
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
Debug > Compile
Compile errors will appear when you attempt to run a Procedure. But ideally, you would identify compile errors prior to attempting to run the procedure.
You can do this by compiling the project ahead of time. To do so, go to Debug > Compile VBA Project.
The compiler will “go to” the first error. Once you fix that error, compile the project again. Repeat until all errors are fixed.
You can tell that all errors are fixed because Compile VBA Project will be grayed out:
OverFlow Error
The VBA OverFlow Error occurs when you attempt to put a value into a variable that is too large. For example, Integer Variables can only contain values between -32,768 to 32,768. If you enter a larger value, you’ll receive an Overflow error:
Instead, you should use the Long Variable to store the larger number.
Other VBA Error Terms
VBA Catch Error
Unlike other programming languages, In VBA there is no Catch Statement. However, you can replicate a Catch Statement by using On Error Resume Next and If Err.Number <> 0 Then. This is covered above in Error Handling with Err.Number.
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
VBA Ignore Error
To ignore errors in VBA, simply use the On Error Resume Next statement:
On Error Resume Next
However, as mentioned above, you should be careful using this statement as it doesn’t fix an error, it just simply ignores the line of code containing the error.
VBA Throw Error / Err.Raise
To through an error in VBA, you use the Err.Raise method.
This line of code will raise Run-time error ’13’: Type mismatch:
Err.Raise (13)
VBA Error Trapping
VBA Error Trapping is just another term for VBA Error Handling.
VBA Error Message
A VBA Error Message looks like this:
When you click ‘Debug’, you’ll see the line of code that is throwing the error:
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
VBA Error Handling in a Loop
The best way to error handle within a Loop is by using On Error Resume Next along with Err.Number to detect if an error has occurred (Remember to use Err.Clear to clear the error after each occurrence).
The example below will divide two numbers (Column A by Column B) and output the result into Column C. If there’s an error, the result will be 0.
Sub test()
Dim cell As Range
On Error Resume Next
For Each cell In Range("a1:a10")
'Set Cell Value
cell.Offset(0, 2).Value = cell.Value / cell.Offset(0, 1).Value
'If Cell.Value is Error then Default to 0
If Err.Number <> 0 Then
cell.Offset(0, 2).Value = 0
Err.Clear
End If
Next
End Sub
VBA Error Handling in Access
All of the above examples work exactly the same in Access VBA as in Excel VBA.
Function DelRecord(frm As Form)
'this function is used to delete a record in a table from a form
On Error GoTo ending
With frm
If .NewRecord Then
.Undo
Exit Function
End If
End With
With frm.RecordsetClone
.Bookmark = frm.Bookmark
.Delete
frm.Requery
End With
Exit Function
ending:
End
End Function
Errors Happen
We may come across several functions in programming languages. In VBA, we are prone to encounter errors like:
- Syntax errors
- Compile time errors
- Runtime errors
These are errors in code which can be handled using error handling methods. For example, you can see some best practices in articles like this one.
In this article, we will discuss some logical errors which will give unexpected output.
Example Scenario
Let us try to copy the contents of a cell to another while the data in the cell has invalid or improper data like a “DIV/0” error which we are not aware of.
In this case, the contents would simply get pasted as-is. But we do not want to use this erroneous data in another sheet or any cell in the same sheet.
In that case, we need an option wherein the copy paste happens only if the source data is error-free. In case of error, we need some specific statement to be pasted there.
The IfError function of VBA can help us achieve this easily.
IfError Function
The IfError function can help point out/display obvious errors in other functions that may not catch our eye easily.
This function is used to prevent mathematical errors or any other errors that occur from a copy paste action when the source value or the resulting value has an error. This function displays resulting values only if they are error-free. If there are errors in the output values, an alternate statement text is displayed.
Syntax:
IfError( < source value> , <alternate text> )
Where:
<source value>
is the cell from which text is copied<alternate text>
is the statement to be used in case the value of source text is erroneous.
Paste One Column’s Cell Values to Another With and Without the IfError Function
Sub ifferror_demo() 'just a for loop to iterate through each row starting from 1 to 20 For i = 1 To 20 ' simply paste the cell values of col 4 to col 6 Cells(i, 6).Value = Cells(i, 4).Value &<pre&>&<code&>' paste the values of col 4 to col 6 only if the values have no errors. If not "invalid numbers" will be pasted. Cells(i, 5).Value = WorksheetFunction.IfError(Cells(i, 4).Value, "Invalid numbers")&>/code&>&</pre&>; Next End Sub
The data in column E pasted using the IfError function looks reasonable and clear.
But the data in col F that has been pasted without using the “IfError” function has not corrected/checked anything for us.
Program That Uses IfError With Vlookup
In this program, we will try to see the price/piece of any item that is selected from a list in a cell.
Price/piece is in col D and the item is in col A. So, we will use “vlookup” here.
I’m setting data validation to list the items in cell H4.
For this, we can go to Data tab-> Data tools-> Data validation.
Choose a list and select the range as the source.
The items are now listed here:
Now I apply the vlookup formula to get the price/piece of the selected item.
Now I select some item from the list in cell H4 that has a “Division by 0 error” in col D, eg: Cake.
To avoid this kind of output, we have to use the “IfError” formula, which can filter out these errors and display a value that the viewers can understand.
Here, the existing vlookup formula is wrapped in an “IfError” formula with the vlookup formula as the first argument. The second argument is an alternate text to be displayed in case the result is erroneous.
The proper value would be displayed in case the output is error-free.
Do the same using a macro code (VBA):
Sub Excel_IFERROR_demo() ' declare a variable of type worksheet Dim ws As Worksheet ' assign the worksheet Set ws = Worksheets("Snackbar") ' apply the Excel IFERROR function with the vlookup function ws.Range("I4") = Application.WorksheetFunction.IfError(Application.VLookup(ws.Range("H4").Value, ws.Range("A1:D13"), 4, False), "CHECK THE VALUE") End Sub
Now, we will delete the formula in cell “I4” and use this macro to fill the data in that cell.
What does this code do?
This declares a worksheet object, assigns the worksheet to it. Then, we assign the vlookup formula to the cell I4 . The formula depends on the value in cell H4.
Whenever we change the value in cell H4, this code should be run to fill the corresponding value in cell I4.
A couple of output results to demonstrate how this code works:
A Program for Mathematical Calculation
This program is for direct division or calculation of price/piece for the item “Roti.”
Sub Excel_IFERROR_demo_2() ' declare a variable of type worksheet Dim ws As Worksheet ' assign the worksheet Set ws = Worksheets("Snackbar") ' apply the Excel IFERROR function with the vlookup function ws.Range("D7") = Application.WorksheetFunction.IfError(ws.Range("B7").Value / ws.Range("C7").Value, "CHECK THE VALUE") End Sub
Here the formula =B7/C6
in the cell D7 is replaced by the output of this code.
A couple of output values for corresponding input values.
Note: Change the values of B7 or C7 or both and run this procedure (code) to see the output in D7.
Summary
“IfError” is available both as a formula and VBA function in Microsoft Excel. This helps us catch the logical faults (e.g.: Math calculations) and not the syntax or compile errors. They are mostly used in Excel formulae directly instead of macros. In the case of automated macro utilities that are large in size, they can be used in the respective VBA code too.
Tagged with: Error, error handling, Errors, Excel, Functions, IfError, Macro, macro code, VBA, VBA For Excel, worksheet functions
Just like we use IFERROR in Excel to know what to do when we encounter an error before every function, we have an inbuilt IFERROR function in VBA used in the same fashion. Since it is a worksheet function, we use this function with the worksheet.function method in VBA, and then we provide the arguments for the function.
IFERROR Function in VBA
It is a crime to expect the code to function without throwing any error. To handle errors in VBA, we have several ways using statements like On Error Resume Next VBAVBA On Error Resume Statement is an error-handling aspect used for ignoring the code line because of which the error occurred and continuing with the next line right after the code line with the error.read more, On Error Resume Goto 0, On Error GoTo Label. VBA error handlers can only proceed further to the next line of code. But if the calculation does not happen, we need to replace the error with another identity word. In this article, we will see how to achieve this by using the VBA IFERROR Function in excelThe IFERROR function in Excel checks a formula (or a cell) for errors and returns a specified value in place of the error.read more.
Table of contents
- IFERROR Function in VBA
- How to use IFERROR in VBA?
- Types of Errors, VBA IFERROR, Can Find
- Recommended Articles
You are free to use this image on your website, templates, etc, Please provide us with an attribution linkArticle Link to be Hyperlinked
For eg:
Source: VBA IFERROR (wallstreetmojo.com)
How to use IFERROR in VBA?
The thing to remember here is it is not a VBA functionVBA functions serve the primary purpose to carry out specific calculations and to return a value. Therefore, in VBA, we use syntax to specify the parameters and data type while defining the function. Such functions are called user-defined functions.read more but rather just a worksheet function.
You can download this VBA IFERROR Excel Template here – VBA IFERROR Excel Template
For example, take the above data only for a demonstration.
Step 1: Define the variable as an integer.
Code:
Sub Iferror_Example1() Dim i As Integer End Sub
Step 2: To perform calculation, open For Next Loop.
Code:
Sub Iferror_Example1() Dim i As Integer For i = 2 To 6 Next i End Sub
Step 3: Inside, write the code as Cells(I,3).Value =
Code:
Sub Iferror_Example1() Dim i As Integer For i = 2 To 6 Cells(i,3).Value = Next i End Sub
Step 4: To access the IFERROR function, we cannot simply type the formula; we need to use the “WorksheetFunction” class.
Code:
Sub Iferror_Example1() Dim i As Integer For i = 2 To 6 Cells(i, 3).Value = WorksheetFunction.If Next i End Sub
Step 5: As you can see in the above image, after inserting the command “WorksheetFunction” class, we get the IFERROR formula. Select the formula.
Code:
Sub Iferror_Example1() Dim i As Integer For i = 2 To 6 Cells(i, 3).Value = WorksheetFunction.IfError( Next i End Sub
Step 6: One of the problems in VBA is that while accessing the worksheet functions, we do not get to see the arguments we have seen in the worksheet. It would help if you were sure about the arguments we are using.
It is the reason before we show you the IFERROR in VBA, We have shown you the syntax of the worksheet function.
The first argument is “Value,” i.e., what cell do you want to check? Before this, apply the calculation in the cell.
Now, in the VBA, apply the codes below.
Code:
Sub Iferror_Example1() Dim i As Integer For i = 2 To 6 Cells(i, 4).Value = WorksheetFunction.IfError(Cells(i, 3).Value, "Not Found") Next i End Sub
Now, the IFERROR function checks for any error in column C. If it finds any error, it will show the result as “Not Found” in column D.
Using the IFERROR function, we can alter the results per our wish. In this case, we have altered the result as “Not Found.” We can change this to your requirement.
Types of Errors, VBA IFERROR, Can Find
Knowing the types of excel errorsErrors in excel are common and often occur at times of applying formulas. The list of nine most common excel errors are — #DIV/0, #N/A, #NAME?, #NULL!, #NUM!, #REF!, #VALUE!, #####, Circular Reference.read more the IFERROR function can handle is important. Below are the kind of errors IFERROR can handle.
#N/A, #VALUE!, #REF!, #DIV/0!, #NUM!, #NAME?, or #NULL!.
Recommended Articles
This article is a guide to VBA IFERROR Function. Here, we learned how to use the VBA IFERROR function in Excel, practical examples, and a downloadable template. Below you can find some useful Excel VBA articles: –
- VBA Type Statement
- VBA Type Mismatch Error
- What is OR Function in VBA?
- Excel VLOOKUP Errors
“Abort, Retry, Fail?” – MS-DOS error message circa 1986
This post provides a complete guide to VBA Error Handing. If you are looking for a quick summary then check out the quick guide table in the first section.
If you are looking for a particular topic on VBA Error Handing then check out the table of contents below(if it’s not visible click on the post header).
If you are new to VBA Error Handling, then you can read the post from start to finish as it is laid out in logical order.
A Quick Guide to Error Handing
Item | Description |
---|---|
On Error Goto 0 | When error occurs, the code stops and displays the error. |
On Error Goto -1 | Clears the current error setting and reverts to the default. |
On Error Resume Next | Ignores the error and continues on. |
On Error Goto [Label] | Goes to a specific label when an error occurs. This allows us to handle the error. |
Err Object | When an error occurs the error information is stored here. |
Err.Number | The number of the error. (Only useful if you need to check a specific error occurred.) |
Err.Description | Contains the error text. |
Err.Source | You can populate this when you use Err.Raise. |
Err.Raise | A function that allows you to generate your own error. |
Error Function | Returns the error text from an error number. Obsolete. |
Error Statement | Simulates an error. Use Err.Raise instead. |
The Webinar
Members of the Webinar Archives can access the webinar for this article by clicking on the image below.
(Note: Archive members have access to the webinar archive.)
Download the Error Handling Library
Introduction
Error Handling refers to code that is written to handle errors which occur when your application is running. These errors are normally caused by something outside your control like a missing file, database being unavailable, data being invalid etc.
If we think an error is likely to occur at some point, it is good practice to write specific code to handle the error if it occurs and deal with it.
For all other errors, we use generic code to deal with them. This is where the VBA error handling statement comes into play. They allow our application to deal gracefully with any errors we weren’t expecting.
To understand error handling we must first understand the different types of errors in VBA.
VBA Errors
There are three types of errors in VBA:
- Syntax
- Compilation
- Runtime
We use error handling to deal with runtime errors. Let’s have a look at each of these error types so that it is clear what a runtime error is.
Syntax Errors
If you have used VBA for any length of time you will have seen a syntax error. When you type a line and press return, VBA will evaluate the syntax and if it is not correct it will display an error message.
For example if you type If and forget the Then keyword, VBA will display the following error message
Some examples of syntax errors are
' then is missing If a > b ' equals is missing after i For i 2 To 7 ' missing right parenthesis b = left("ABCD",1
Syntax errors relate to one line only. They occur when the syntax of one line is incorrect.
Note: You can turn off the Syntax error dialog by going to Tools->Options and checking off “Auto Syntax Check”. The line will still appear red if there is an error but the dialog will not appear.
Compilation Errors
Compilation errors occur over more than one line. The syntax is correct on a single line but is incorrect when all the project code is taken into account.
Examples of compilation errors are:
- If statement without corresponding End If statement
- For without Next
- Select without End Select
- Calling a Sub or Function that does not exist
- Calling a Sub or Function with the wrong parameters
- Giving a Sub or Function the same name as a module
- Variables not declared(Option Explicit must be present at the top of the module)
The following screenshot shows a compilation error that occurs when a For loop has no matching Next statement.
Using Debug->Compile
To find compilation errors, we use Debug->Compile VBA Project from the Visual Basic menu.
When you select Debug->Compile, VBA displays the first error it comes across.
When this error is fixed, you can run Compile again and VBA will then find the next error.
Debug->Compile will also include syntax errors in it’s search which is very useful.
If there are no errors left and you run Debug->Compile , it may appear that nothing happened. However, “Compile” will be grayed out in the Debug menu. This means your application has no compilation errors at the current time.
Debug->Compile Error Summary
- Debug->Compile finds compilation(project wide) errors.
- It will also find syntax errors.
- It finds one error each time you use it.
- When there are no compilation errors left the Compile option will appear grayed out in the menu.
Debug->Compile Usage
You should always use Debug->Compile before you run your code. This ensures that your code has no compilation errors when you run it.
If you do not run Debug->Compile then VBA may find compile errors when it runs. These should not be confused with Runtime errors.
Runtime Errors
Runtime errors occur when your application is running. They are normally outside of your control but can be caused by errors in your code.
For example, imagine your application reads from an external workbook. If this file gets deleted then VBA will display an error when your code tries to open it.
Other examples of runtime errors are
- a database not being available
- the user entering invalid data
- a cell containing text instead of a number
As we have seen, the purpose of error handling is to deal with runtime errors when they occur.
Expected Versus Unexpected Errors
When we think a runtime error could occur we put code in place to handle it. For example, we would normally put code in place to deal with a file not being found.
The following code checks if the file exists before it tries to open it. If the file does not exist then a user friendly message is displayed and the code exits the sub.
' https://excelmacromastery.com/ Sub OpenFile() Dim sFile As String sFile = "C:docsdata.xlsx" ' Use Dir to check if file exists If Dir(sFile) = "" Then ' if file does not exist display message MsgBox "Could not find the file " & sFile Exit Sub End If ' Code will only reach here if file exists Workbooks.Open sFile End Sub
When we think an error is likely to occur at some point, it is good practice to add code to handle the situation. We normally refer to these errors as expected errors.
If we don’t have specific code to handle an error it is considered an unexpected error. We use the VBA error handling statements to handle the unexpected errors.
Runtime Errors that are not VBA Errors
Before we look at the VBA Handling there is one type of error we must mention. Some runtime errors are not considered errors by VBA but only by the user.
Let me explain this with an example. Imagine you have an application that requires you to add the values in the variables a and b
result = a + b
Let’s say you mistakenly use an asterisk instead of the plus sign
result = a * b
This is not a VBA error. Your code syntax is perfectly legal. However, from your requirements point of view it is an error.
These errors cannot be dealt with using error handling as they obviously won’t generate any error. You can deal with these errors using Unit Testing and Assertions. I have an in-depth post about using VBA assertions – see How to Make Your Code BulletProof.
The On Error Statement
As we have seen there are two ways to treat runtime errors
- Expected errors – write specific code to handle them.
- Unexpected errors – use VBA error handling statements to handle them.
The VBA On Error statement is used for error handling. This statement performs some action when an error occurs during runtime.
There are four different ways to use this statement
- On Error GoTo 0 – the code stops at the line with the error and displays a message.
- On Error Resume Next – the code moves to next line. No error message is displayed.
- On Error GoTo [label] – the code moves to a specific line or label. No error message is displayed. This is the one we use for error handling.
- On Error GoTo -1 – clears the current error.
Let’s look at each of these statements in turn.
On Error GoTo 0
This is the default behavior of VBA. In other words, if you don’t use On Error then this is the behavior you will see.
When an error occurs, VBA stops on the line with the error and displays the error message. The application requires user intervention with the code before it can continue. This could be fixing the error or restarting the application. In this scenario no error handling takes place.
Let’s look at an example. In the following code, we have not used any On Error line so VBA will use the On Error GoTo 0 behavior by default.
' https://excelmacromastery.com/ Sub UsingDefault() Dim x As Long, y As Long x = 6 y = 6 / 0 x = 7 End Sub
The second assignment line results in a divide by zero error. When we run this code we will get the error message shown in the screenshot below
When the error appears you can choose End or Debug
If you select End then the application simply stops.
If you select Debug the application stops on the error line as the screenshot below shows
This behaviour is fine when you are writing VBA code as it shows you the exact line with the error.
This behavior is unsuitable for an application that you are given to a user. These errors look unprofessional and they make the application look unstable.
An error like this is essentially the application crashing. The user cannot continue on without restarting the application. They may not use it at all until you fix the error for them.
By using On Error GoTo [label] we can give the user a more controlled error message. It also prevents the application stopping. We can get the application to perform in a predefined manner.
On Error Resume Next
Using On Error Resume Next tells VBA to ignore the error and continue on.
There are specific occasions when this is useful. Most of the time you should avoid using it.
If we add Resume Next to our example Sub then VBA will ignore the divide by zero error
' https://excelmacromastery.com/ Sub UsingResumeNext() On Error Resume Next Dim x As Long, y As Long x = 6 y = 6 / 0 x = 7 End Sub
It is not a good idea to do this. If you ignore the error, then the behavior can be unpredictable. The error can affect the application in multiple ways.You could end up with invalid data. The problem is that you aren’t aware that something went wrong because you have suppressed the error.
The code below is an example of where using Resume Next is valid
' https://excelmacromastery.com/ Sub SendMail() On Error Resume Next ' Requires Reference: ' Microsoft Outlook 15.0 Object Library Dim Outlook As Outlook.Application Set Outlook = New Outlook.Application If Outlook Is Nothing Then MsgBox "Cannot create Microsoft Outlook session." _ & " The email will not be sent." Exit Sub End If End Sub
In this code we are checking to see if Microsoft Outlook is available on a computer. All we want to know is if it is available or not. We are not interested in the specific error.
In the code above, we continue on if there is an error. Then in the next line we check the value of the Outlook variable. If there has been an error then the value of this variable will be set to Nothing.
This is an example of when Resume could be useful. The point is that even though we use Resume we are still checking for the error. The vast majority of the time you will not need to use Resume.
On Error GoTo [label]
This is how we use Error Handling in VBA. It is the equivalent of the Try and Catch functionality you see in languages such as C# and Java.
When an error occurs you send the error to a specific label. It is normally at the bottom of the sub.
Let’s apply this to the sub we have been using
' https://excelmacromastery.com/ Sub UsingGotoLine() On Error GoTo eh Dim x As Long, y As Long x = 6 y = 6 / 0 x = 7 Done: Exit Sub eh: MsgBox "The following error occurred: " & Err.Description End Sub
The screenshot below shows what happens when an error occurs
VBA jumps to the eh label because we specified this in the On Error Goto line.
Note 1: The label we use in the On…GoTo statement, must be in the current Sub/Function. If not you will get a compilation error.
Note 2: When an error occurs when using On Error GoTo [label], the error handling returns to the default behaviour i.e. The code will stop on the line with the error and display the error message. See the next section for more information about this.
On Error GoTo -1
This statement is different than the other three. It is used to clear the current error rather than setting a particular behaviour.
When an error occurs using On Error GoTo [label], the error handling behaviour returns to the default behaviour i.e. “On Error GoTo 0”. That means that if another error occurs the code will stop on the current line.
This behaviour only applies to the current sub. Once we exit the sub, the error will be cleared automatically.
Take a look at the code below. The first error will cause the code to jump to the eh label. The second error will stop on the line with the 1034 error.
' https://excelmacromastery.com/ Sub TwoErrors() On Error Goto eh ' generate "Type mismatch" error Error (13) Done: Exit Sub eh: ' generate "Application-defined" error Error (1034) End Sub
If we add further error handling it will not work as the error trap has not been cleared.
In the code below we have added the line
On Error Goto eh_other
after we catch the first error.
This has no effect as the error has not been cleared. In other words the code will stop on the line with the error and display the message.
' https://excelmacromastery.com/ Sub TwoErrors() On Error Goto eh ' generate "Type mismatch" error Error (13) Done: Exit Sub eh: On Error Goto eh_other ' generate "Application-defined" error Error (1034) Exit Sub eh_other: Debug.Print "eh_other " & Err.Description End Sub
To clear the error we use On Error GoTo -1. Think of it like setting a mouse trap. When the trap goes off you need to set it again.
In the code below we add this line and the second error will now cause the code to jump to the eh_other label
' https://excelmacromastery.com/ Sub TwoErrors() On Error Goto eh ' generate "Type mismatch" error Error (13) Done: Exit Sub eh: ' clear error On Error Goto -1 On Error Goto eh_other ' generate "Application-defined" error Error (1034) Exit Sub eh_other: Debug.Print "eh_other " & Err.Description End Sub
Note 1: There are probably rare cases where using On Error GoTo -1 is useful. In most cases using Resume Next is better as it clears the error and resumes the code at the next line after the error occurs.
Note 2: The Err Object has a member Clear. Using Clear clears the text and numbers in the Err object, but it does NOT reset the error.
Using On Error
As we have seen, VBA will do one of three things when an error occurs
- Stop and display the error.
- Ignore the error and continue on.
- Jump to a specific line.
VBA will always be set to one of these behaviors. When you use On Error, VBA will change to the behaviour you specify and forget about any previous behavior.
In the following Sub, VBA changes the error behaviour each time we use the On Error statement
' https://excelmacromastery.com/ Sub ErrorStates() Dim x As Long ' Go to eh label if error On Error Goto eh ' this will ignore the error on the following line On Error Resume Next x = 1 / 0 ' this will display an error message on the following line On Error Goto 0 x = 1 / 0 Done: Exit Sub eh: Debug.Print Err.Description End Sub
Resume Next
The Resume Next statement is used to clear the error and then resume the code from the line after where the error occurred.
If your code can have multiple errors and you want to keep detecting them then this line is very useful.
For example, in the following code we want to resume the code after the error has been reported:
Private Sub Main() On Error Goto eh Dim i As Long For i = 1 To 3 ' Generate type mismatch error Error 13 Next i done: Exit Sub eh: Debug.Print i, Err.Description End Sub
We could use On Error Goto -1 to clear the code and then use a goto statement to go back to the code like this:
Private Sub Main() On Error Goto eh Dim i As Long For i = 1 To 3 ' Generate type mismatch error Error 13 continue: Next i done: Exit Sub eh: Debug.Print i, Err.Description On Error Goto -1 ' clear the error Goto continue ' return to the code End Sub
The Resume Next provides a nicer way of doing it and it always means the code is much clearer and easier to understand:
Private Sub Main() On Error Goto eh Dim i As Long For i = 1 To 3 ' Generate type mismatch error Error 13 continue: Next i done: Exit Sub eh: Debug.Print i, Err.Description ' clear the error and return to the code Resume Next End Sub
The Err Object
When an error occurs you can view details of the error using the Err object.
When an runtime error occurs, VBA automatically fills the Err object with details.
The code below will print “Error Number: 13 Type Mismatch” which occurs when we try to place a string value in the long integer total
' https://excelmacromastery.com/ Sub UsingErr() On Error Goto eh Dim total As Long total = "aa" Done: Exit Sub eh: Debug.Print "Error number: " & Err.Number _ & " " & Err.Description End Sub
The Err.Description provides details of the error that occurs. This is the text you normally see when an error occurs e.g. “Type Mismatch”
The Err.Number is the ID number of the error e.g. the error number for “Type Mismatch” is 13. The only time you really need this is if you are checking that a specific error occurred and this is only necessary on rare occasions.
The Err.Source property seems like a great idea but it does not work for a VBA error. The source will return the project name, which hardly narrows down where the error occurred. However, if you create an error using Err.Raise you can set the source yourself and this can be very useful.
Getting the Line Number
The Erl function is used to return the line number where the error occurs.
It often causes confusion. In the following code, Erl will return zero
' https://excelmacromastery.com/ Sub UsingErr() On Error Goto eh Dim val As Long val = "aa" Done: Exit Sub eh: Debug.Print Erl End Sub
This is because there are no line numbers present. Most people don’t realise it but VBA allows you to have line numbers.
If we change the Sub above to have line number it will now print out 20
' https://excelmacromastery.com/ Sub UsingErr() 10 On Error Goto eh Dim val As Long 20 val = "aa" Done: 30 Exit Sub eh: 40 Debug.Print Erl End Sub
Adding line numbers to your code manually is cumbersome. However there are tools available that will allow you to easily add and remove line numbers to a sub.
When you are finished working on a project and hand it over to the user it can be useful to add line numbers at this point. If you use the error handling strategy in the last section of this post, then VBA will report the line where the error occurred.
Using Err.Raise
Err.Raise allows us to create errors. We can use it to create custom errors for our application which is very useful. It is the equivalent of the Throw statement in JavaC#.
The format is as follows
Err.Raise [error number], [error source], [error description]
Let’s look at a simple example. Imagine we want to ensure that a cell has an entry that has a length of 5 characters. We could have a specific message for this
' https://excelmacromastery.com/ Public Const ERROR_INVALID_DATA As Long = vbObjectError + 513 Sub ReadWorksheet() On Error Goto eh If Len(Sheet1.Range("A1")) <> 5 Then Err.Raise ERROR_INVALID_DATA, "ReadWorksheet" _ , "The value in the cell A1 must have exactly 5 characters." End If ' continue on if cell has valid data Dim id As String id = Sheet1.Range("A1") Done: Exit Sub eh: ' Err.Raise will send code to here MsgBox "Error found: " & Err.Description End Sub
When we create an error using Err.Raise we need to give it a number. We can use any number from 513 to 65535 for our error. We must use vbObjectError with the number e.g.
Err.Raise vbObjectError + 513
Using Err.Clear
Err.Clear is used to clear the text and numbers from the Err.Object. In other words, it clears the description and number.If you want the clear the actual error you can use either On Error GoTo -1 or Resume Next
It is rare that you will need to use Err.Clear but let’s have a look at an example where you might.
In the code below we are counting the number of errors that will occur. To keep it simple we are generating an error for each odd number.
We check the error number each time we go through the loop. If the number does not equal zero then an error has occurred. Once we count the error we need to set the error number back to zero so it is ready to check for the next error.
' https://excelmacromastery.com/ Sub UsingErrClear() Dim count As Long, i As Long ' Continue if error as we will check the error number On Error Resume Next For i = 0 To 9 ' generate error for every second one If i Mod 2 = 0 Then Error (13) ' Check for error If Err.Number <> 0 Then count = count + 1 Err.Clear ' Clear Err once it is counted End If Next Debug.Print "The number of errors was: " & count End Sub
Note 1: Err.Clear resets the text and numbers in the error object but it does not clear the error – see Resume Next Or On Error GoTo -1 for more information about clearing the actual error.
Logging
Logging means writing information from your application when it is running. When an error occurs you can write the details to a text file so you have a record of the error.
The code below shows a very simple logging procedure
' https://excelmacromastery.com/ Sub Logger(sType As String, sSource As String, sDetails As String) Dim sFilename As String sFilename = "C:templogging.txt" ' Archive file at certain size If FileLen(sFilename) > 20000 Then FileCopy sFilename _ , Replace(sFilename, ".txt", Format(Now, "ddmmyyyy hhmmss.txt")) Kill sFilename End If ' Open the file to write Dim filenumber As Variant filenumber = FreeFile Open sFilename For Append As #filenumber Print #filenumber, CStr(Now) & "," & sType & "," & sSource _ & "," & sDetails & "," & Application.UserName Close #filenumber End Sub
You can use it like this
' Create unique error number ' https://excelmacromastery.com/ Public Const ERROR_DATA_MISSING As Long = vbObjectError + 514 Sub CreateReport() On Error Goto eh If Sheet1.Range("A1") = "" Then Err.Raise ERROR_DATA_MISSING, "CreateReport", "Data is missing from Cell A1" End If ' other code here Done: Exit Sub eh: Logger "Error", Err.Source, Err.Description End Sub
The log is not only for recording errors. You can record other information as the application runs. When an error occurs you can then check the sequence of events before an error occurred.
Below is an example of logging. How you implement logging really depends on the nature of the application and how useful it will be:
' https://excelmacromastery.com/ Sub ReadingData() Logger "Information", "ReadingData()", "Starting to read data." Dim coll As New Collection ' add data to the collection coll.Add "Apple" coll.Add "Pear" If coll.Count < 3 Then Logger "Warning", "ReadingData()", "Number of data items is low." End If Logger "Information", "ReadingData()", "Number of data items is " & coll.Count Logger "Information", "ReadingData()", "Finished reading data." End Sub
Having a lot of information when dealing with an error can be very useful. Often the user may not give you accurate information about the error that occurred. By looking at the log you can get more accurate information about the information.
Other Error Related Items
This section covers some of the other Error Handling tools that VBA has. These items are considered obsolete but I have included them as they may exist in legacy code.
Error Function
The Error Function is used to print the error description from a given error number. It is included in VBA for backward compatibility and is not needed because you can use the Err.Description instead.
Below are some examples:
' Print the text "Division by zero" Debug.Print Error(11) ' Print the text "Type mismatch" Debug.Print Error(13) ' Print the text "File not found" Debug.Print Error(53)
Error Statement
The Error statement allows you to simulate an error. It is included in VBA for backward compatibility. You should use Err.Raise instead.
In the following code we simulate a “Divide by zero” error.
' https://excelmacromastery.com/ Sub SimDivError() On Error Goto eh ' This will create a division by zero error Error 11 Exit Sub eh: Debug.Print Err.Number, Err.Description End Sub
This statement is included in VBA for backward compatibility. You should use Err.Raise instead.
A Simple Error Handling Strategy
With all the different options you may be confused about how to use error handling in VBA. In this section, I’m going to show you how to implement a simple error handling strategy that you can use in all your applications.
The Basic Implementation
This is a simple overview of our strategy
- Place the On Error GoTo Label line at the start of our topmost sub.
- Place the error handling Label at the end of our topmost sub.
- If an expected error occurs then handle it and continue.
- If the application cannot continue then use Err.Raise to jump to the error handling label.
- If an unexpected error occurs the code will automatically jump to the error handling label.
The following image shows an overview of how this looks
The following code shows a simple implementation of this strategy:
' https://excelmacromastery.com/ Public Const ERROR_NO_ACCOUNTS As Long = vbObjectError + 514 Sub BuildReport() On Error Goto eh ' If error in ReadAccounts then jump to error ReadAccounts ' Do something with the code Done: Exit Sub eh: ' All errors will jump to here MsgBox Err.Source & ": The following error occured " & Err.Description End Sub Sub ReadAccounts() ' EXPECTED ERROR - Can be handled by the code ' Application can handle A1 being zero If Sheet1.Range("A1") = 0 Then Sheet1.Range("A1") = 1 End If ' EXPECTED ERROR - cannot be handled by the code ' Application cannot continue if no accounts workbook If Dir("C:DocsAccount.xlsx") = "" Then Err.Raise ERROR_NO_ACCOUNTS, "UsingErr" _ , "There are no accounts present for this month." End If ' UNEXPECTED ERROR - cannot be handled by the code ' If cell B3 contains text we will get a type mismatch error Dim total As Long total = Sheet1.Range("B3") ' continue on and read accounts End Sub
This is a nice way of implementing error handling because
- We don’t need to add error handling code to every sub.
- If an error occurs then VBA exits the application gracefully.
A Complete Error Handling Strategy
The above strategy has one major drawback. It doesn’t provide any information about the error. It is better than having no strategy as it prevents the application crashing. But that is the only real benefit.
VBA doesn’t fill Err.Source with anything useful so we have to do this ourselves.
In this section, I am going to introduce a more complete error strategy. I have written two subs that perform all the heavy lifting so all you have to do is add them to your project.
The purpose of this strategy is to provide you with the Stack* and line number when an error exists.
*The Stack is the list of sub/functions that were currently in use when the error occurred.
This is our strategy
- Place error handling in all the subs.
- When an error occurs, the error handler adds details to the error and raises it again.
- When the error reaches the topmost sub it is displayed.
We are simply “bubbling” the error to the top. The following diagram shows a simple visual of what happens when an error occurs in Sub3
The only messy part to this is formatting the strings correctly. I have written two subs that handle this, so it is taken care of for you.
There are the two helper subs, RaiseError and DisplayError. You can download the library below:
An Example of using this strategy
Here is a simple coding example that uses these subs. In this strategy, we don’t place any code in the topmost sub. We only call subs from it.
' https://excelmacromastery.com/ Sub Topmost() On Error Goto EH Level1 Done: Exit Sub EH: DisplayError Err.source, Err.Description, "Module1.Topmost", Erl End Sub Sub Level1() On Error Goto EH Level2 Done: Exit Sub EH: RaiseError Err.Number, Err.source, "Module1.Level1", Err.Description, Erl End Sub Sub Level2() On Error Goto EH ' Error here Dim a As Long a = "7 / 0" Done: Exit Sub EH: RaiseError Err.Number, Err.source, "Module1.Level2", Err.Description, Erl End Sub
The result looks like this:
If your project has line numbers the result will include the line number of the error:
Error Handling in a Nutshell
- Error Handling is used to handle errors that occur when your application is running.
- You write specific code to handle expected errors. You use the VBA error handling statement On Error GoTo [label] to send VBA to a label when an unexpected error occurs.
- You can get details of the error from Err.Description.
- You can create your own error using Err.Raise.
- Using one On Error statement in the top most sub will catch all errors in subs that are called from here.
- If you want to record the name of the Sub with the error, you can update the error and rethrow it.
- You can use a log to record information about the application as it is running.
What’s Next?
Free VBA Tutorial If you are new to VBA or you want to sharpen your existing VBA skills then why not try out the The Ultimate VBA Tutorial.
Related Training: Get full access to the Excel VBA training webinars and all the tutorials.
(NOTE: Planning to build or manage a VBA Application? Learn how to build 10 Excel VBA applications from scratch.)
If VBA can’t execute a statement (command) then a run-time error occurs. By default Excel deals with these, so when a run-time error occurs, you’ll see a default error message like this:
But you can change this and instruct Excel to allow your code to deal with run-time errors.
NOTE : I’m going to use the terms sub, function and procedure interchangeably. For the purposes of this article they all mean the same thing – a chunk of code written to do a particular thing.
The On Error Statement
To instruct Excel what to do when an error occurs, you use the On Error statement. You can use On Error in four ways:
On Error GoTo 0 On Error Resume Next On Error GoTo [label] On Error GoTo -1
On Error GoTo 0
This is the default mode and is already turned on when you start writing your code. You don’t need to use an On Error GoTo 0 statement at the start of your VBA.
In this mode VBA displays the standard style error message box, and gives you the choice to Debug the code (enter VBA editor and use debugging tools) or End code execution.
You would use On Error GoTo 0 to turn default error handling back on if you have previously told VBA to deal with errors in some other way e.g. by using On Error Resume Next.
On Error Resume Next
On Error Resume Next tells VBA to continue executing statements immediately after the statement that generated the error.
On Error Resume Next allows your code to continue running even if an error occurs. Resume Next does not fix an error, it just ignores it. This can be good and bad.
The Good?
If you know that your code could generate an error, then using Resume Next can prevent an interruption in code execution.
For example, we want to create a file, but I want to make sure a file with the same name doesn’t already exist. To do this, I will attempt to delete the file, and of course if it doesn’t already exist, an error will occur.
I don’t care if an error occurs. If it does, the file doesn’t exist and that’s fine for what I want to do. So before I attempt to delete the file, I instruct VBA to ignore the error.
Sub DeleteFile() Dim FilePath As String FilePath = "d:tempsomefile.csv" On Error Resume Next 'Delete the file Kill FilePath 'If the file doesn't exist the Kill statement 'generates an error. 'But I have assumed that is ok as it indicates that 'I am ok to create a new file with the same filename 'This is a bad assumption - see the next sub 'UnhandledError() End Sub
The Bad
But hang on. What if the file I am trying to delete is read only? If it is I will get an error when I try to delete it. I’ve assumed that I will only get an error if the file isn’t there. So an error caused by trying to delete a read only file will get missed.
And If I then try to create a new file with the same name, or open it for writing data to it, I will generate more errors and they will be missed too.
Sub UnhandledError() Dim FilePath As String FilePath = "d:tempsomefile.csv" On Error Resume Next 'Delete the file Kill FilePath 'But if the file is read-only I can't delete it 'and the Kill statement generates an error 'I can't now create a new file with the same name 'Trying to Open the file for writing data to it will 'also generate an error but it will be missed as 'we've told VBA to continue executing code if an 'error occurs Open FilePath For Output As #1 Write #1, "Some data" Close #1 End Sub
If you do use On Error Resume Next you should immediately turn default error handling back on (or turn on your custom error handler – see below)
Be careful when using On Error Resume Next. You are better off seeing if an error occurred by checking the Err object (see below). Doing this can tell you the error number and help you figure out exactly what happened.
On Error GoTo [LABEL]
If an error occurs, this transfers code execution to the line following the label. This is typically used to specify your own error handling code.
None of the code between the line generating the error and the label is executed.
Error Handlers
So you write your own error handling code and use On Error GoTo [LABEL] to instruct VBA to use your code to deal with errors.
You can place your error-handling code anywhere in a procedure, but typically it is placed at the end.
Your error handler should either fix the error and resume code execution, or terminate the routine gracefully.
Sub ErrorHandler() Dim num As Integer On Error GoTo ErrHandler num = 1 / 0 MsgBox "This line is not executed" Exit sub ErrHandler: MsgBox "Oops, an error has occured." & vbCrLf & vbCrLf & "Error Code : " & Err.Number & " , " & Err.Description End Sub
As VBA will execute each line of code in turn going from top to bottom, if no error is generated then it will execute your error handling code when it gets to that point in your sub.
To prevent this happening, use an Exit Sub, Exit Function, or Exit Property statement before your error handling routine.
In the example above, if the value assigned to num was valid e.g. num = 1/1, then we don’t want the code beneath ErrHandler: executed. So just before the ErrHandler: label, I’ve used an Exit Sub statement.
Multiple Error Handlers
You can have more than one error handler in a routine, but only one of them can be active at any time.
You could have something like:
Sub MultipleErrorHandlers() On Error GoTo ErrHandler1 [some code] On Error GoTo ErrHandler2 [some code] Exit Sub ErrHandler1: [ErrHandler1 Code] Exit Sub ErrHandler2: [ErrHandler1 Code] Exit Sub End Sub
If an error occurs between On Error GoTo ErrHandler1 and On Error GoTo ErrHandler2 then the ErrHandler1 code is executed.
If an error occurs after On Error GoTo ErrHandler2 then the ErrHandler2 code is executed.
NOTE: Notice that at the end of each error handling routine is an Exit Sub statement. If I didn’t use these, when the ErrHandler1 code is finished executing, VBA could just continue on down to the next line and execute the ErrHandler2 code as well.
Strictly speaking I don’t need the Exit Sub at the end of the ErrHandler2 code, as it is the last line in the sub, but it is a good habit to get into.
Err object
When an error occurs the Err object contains information about the error like the error number and a description of the error.
As any given line of code can generate multiple errors it’s a good idea to examine the Err object to determine what you want to do in your code.
Err.Number gives you the error number, and Err.Description gives you a description of the error.
Sub CheckErrObject() Dim FilePath As String FilePath = "d:tempsomefile.csv" On Error GoTo ErrHandler 'Delete the file Kill FilePath Open FilePath For Output As #1 Write #1, "Some data" Close #1 Exit Sub ErrHandler: Select Case Err.Number Case 53 ' File doesn't exist Err.Clear ' Clear the error Case 75 ' File is Read Only MsgBox "Error Number : " & Err.Number & vbCrLf & vbCrLf & Err.Description Exit Sub Case Else ' Code to handle other errors End Select Resume Next ' Continue executing code after line that generated error End Sub
Resume
The Resume statement tells VBA to resume executing code at a specified point. Resume can only be used in an error handling routine, any other use will generate an error.
Resume takes three forms:
Resume Resume Next Resume [label]
Using just Resume causes execution to resume at the same line of code that caused the error. If you haven’t fixed the error, your code will begin an infinite loop as it switches between the line of code generating the error and the error handling routine.
If you look at the example sub Resume_Next() which is below, num = 1 / 0 causes a Divide by 0 error. I’ve instructed VBA to use my error handler, called ErrHandler.
In ErrHandler I’ve attempted to fix the error by assigning num the value 1. If I then used only Resume, all that would happen is that VBA would go back to num = 1 / 0 and another Divide by 0 error would be generated.
Instead, I use Resume Next to carry on executing code at the line after the one causing the error.
In doing so I have handled the error by assigning the value 1 to num, and execution will continue without another error at the line result = num / 1
Sub Resume_Next() Dim num As Integer Dim result As Integer On Error GoTo ErrHandler num = 1 / 0 result = num / 1 Exit Sub ErrHandler: num = 1 Resume Next End Sub
Resume [label] passes code execution to the line with that label.
Sub Resume_Next() Dim num As Integer Dim result As Integer On Error GoTo ErrHandler num = 1 / 0 result = num / 1 MyLabel: ‘Code execution starts again from here result = num * 1 Exit Sub ErrHandler: num = 1 Resume MyLabel End Sub
Whenever you use Resume it clears the Err object.
Error Handling With Multiple Procedures
Every sub/function doesn’t have to have an error handler. If an error occurs, VBA will use the last On Error statement to determine what happens.
If an On Error statement has been used in a procedure and an error occurs in that procedure, then that error is handled as I’ve just described.
But if an error occurs in a sub that hasn’t used an On Error statement, VBA goes back through procedure calls until it finds an On Error directive.
Let’s look at an example with three subs.
SubOne() calls SubTwo(). SubTwo calls SubThree(), and has some code of its own to execute. SubThree() carries out a calculation.
Sub SubOne() On Error GoTo ErrHandler SubTwo Exit Sub ErrHandler: MsgBox "Error caught in SubOne" End Sub Sub SubTwo() SubThree MsgBox "No errors here" End Sub Sub SubThree() Dim num As Integer num = 1 / 0 End Sub
SubOne() has an error handler routine, ErrHandler, and has instructed VBA to use it.
SubTwo() will display a message on screen after it’s call to SubThree() has finished.
However SubThree() generates a Divide by 0 error.
SubThree() hasn’t used an On Error statement to tell VBA what to do if an error occurs, so VBA goes back to SubTwo(). That also doesn’t have an On Error statement so VBA goes back to SubOne().
Here we have our error handler and the code in it is executed.
Note that the message «No errors here» in SubTwo() is not displayed because that line of code is not executed.
When SubThree() generated an error, code execution went back to the error handler in SubOne() and any code in SubTwo() after the call to SubThree() is missed out.
On Error GoTo -1
This resets the current error. It’s the equivalent of using Err.Clear.
You can see that in this sub, after the Divide By 0 error is generated, after On Error GoTo -1 is used, Err.Number is 0 (no error) and Err.Description is empty.
Sub GoToMinus1() Dim num As Integer On Error Resume Next num = 1 / 0 'If error is Divide by Zero If Err.Number = 11 Then MsgBox "Error Code : " & Err.Number & " , " & Err.Description On Error GoTo -1 MsgBox "Error Code : " & Err.Number & " , " & Err.Description End If End Sub
Sample Code
Enter your email address below to download the sample workbook.
By submitting your email address you agree that we can email you our Excel newsletter.
Избегание условий ошибки
Когда возникает ошибка времени выполнения, хороший код должен ее обрабатывать. Лучшей стратегией обработки ошибок является запись кода, который проверяет условия ошибки и просто избегает выполнения кода, который приводит к ошибке выполнения.
Одним из ключевых элементов сокращения ошибок во время выполнения является запись небольших процедур, которые делают одно . Чем меньше процедур процедур приходится терпеть неудачу, тем проще код в целом — отлаживать.
Избежать ошибки времени выполнения 91 — Объект или С заблокированной переменной блока:
Эта ошибка будет повышена, если объект используется до назначения ссылки. Возможно, у вас есть процедура, которая получает параметр объекта:
Private Sub DoSomething(ByVal target As Worksheet)
Debug.Print target.Name
End Sub
Если target
не назначена ссылка, приведенный выше код вызовет ошибку, которую легко избежать, проверяя, содержит ли объект фактическую ссылку на объект:
Private Sub DoSomething(ByVal target As Worksheet)
If target Is Nothing Then Exit Sub
Debug.Print target.Name
End Sub
Если target
назначению не присвоена ссылка, то непризнанная ссылка никогда не используется, и ошибка не возникает.
Этот способ раннего выхода из процедуры, когда один или несколько параметров недопустимы, называется предложением охраны .
Избегайте ошибки времени выполнения 9 — Подкласс вне диапазона:
Эта ошибка возникает при доступе к массиву за пределами его границ.
Private Sub DoSomething(ByVal index As Integer)
Debug.Print ActiveWorkbook.Worksheets(index)
End Sub
Учитывая, что индекс больше, чем количество листов в ActiveWorkbook
, приведенный выше код вызовет ошибку времени выполнения. Простое предложение охраны может избежать этого:
Private Sub DoSomething(ByVal index As Integer)
If index > ActiveWorkbook.Worksheets.Count Or index <= 0 Then Exit Sub
Debug.Print ActiveWorkbook.Worksheets(index)
End Sub
Большинство ошибок времени выполнения можно избежать, тщательно проверив значения, которые мы используем, прежде чем мы их используем, и разветвляемся на другом пути выполнения, соответственно, используя простой оператор If
— в сторожевых предложениях, который не делает предположений и не проверяет параметры процедуры, или даже в тело более крупных процедур.
Оператор Error
Даже с защитными пунктами, один не может реально всегда учитывать все возможные ошибки , которые могут быть подняты в теле процедуры. Оператор On Error GoTo
инструктирует VBA перейти к метке линии и ввести «режим обработки ошибок» всякий раз, когда во время выполнения происходит непредвиденная ошибка. После обработки ошибки, код может возобновить обратно в «нормальное» исполнение с помощью Resume
ключевое слово.
Линейные метки обозначают подпрограммы : потому что подпрограммы исходят из устаревшего кода BASIC и используют GoSub
GoTo
и GoSub
и Return
чтобы вернуться к «основной» процедуре, довольно легко написать жесткий код спагетти, если все не строго структурировано , По этой причине лучше всего:
- процедура имеет одну и только одну подпрограмму обработки ошибок
- подпрограмма обработки ошибок работает только в состоянии ошибки
Это означает, что процедура, которая обрабатывает его ошибки, должна быть структурирована следующим образом:
Private Sub DoSomething()
On Error GoTo CleanFail
'procedure code here
CleanExit:
'cleanup code here
Exit Sub
CleanFail:
'error-handling code here
Resume CleanExit
End Sub
Стратегии обработки ошибок
Иногда вы хотите обрабатывать разные ошибки с помощью разных действий. В этом случае вы будете проверять глобальный объект Err
, который будет содержать информацию об ошибке, которая была поднята, и действовать соответственно:
CleanExit:
Exit Sub
CleanFail:
Select Case Err.Number
Case 9
MsgBox "Specified number doesn't exist. Please try again.", vbExclamation
Resume
Case 91
'woah there, this shouldn't be happening.
Stop 'execution will break here
Resume 'hit F8 to jump to the line that raised the error
Case Else
MsgBox "An unexpected error has occurred:" & vbNewLine & Err.Description, vbCritical
Resume CleanExit
End Select
End Sub
В качестве общего руководства рассмотрите возможность включения обработки ошибок для всей подпрограммы или функции и обработайте все ошибки, которые могут возникнуть в пределах ее области действия. Если вам нужно обрабатывать ошибки только в секции небольшого сечения кода — включить и выключить обработку ошибок на одном уровне:
Private Sub DoSomething(CheckValue as Long)
If CheckValue = 0 Then
On Error GoTo ErrorHandler ' turn error handling on
' code that may result in error
On Error GoTo 0 ' turn error handling off - same level
End If
CleanExit:
Exit Sub
ErrorHandler:
' error handling code here
' do not turn off error handling here
Resume
End Sub
Номера строк
VBA поддерживает номера строк в стиле legacy (например, QBASIC). Скрытое свойство Erl
можно использовать для идентификации номера строки, которая вызвала последнюю ошибку. Если вы не используете номера строк, Erl
только вернет 0.
Sub DoSomething()
10 On Error GoTo 50
20 Debug.Print 42 / 0
30 Exit Sub
40
50 Debug.Print "Error raised on line " & Erl ' returns 20
End Sub
Если вы используете номера строк, но не последовательно, а затем Erl
возвращает номер последней строки перед командой, вызвавшей ошибку.
Sub DoSomething()
10 On Error GoTo 50
Debug.Print 42 / 0
30 Exit Sub
50 Debug.Print "Error raised on line " & Erl 'returns 10
End Sub
Имейте в виду, что Erl
также имеет только Integer
точность и будет бесшумно переполняться. Это означает, что номера строк за пределами целочисленного диапазона дадут неверные результаты:
Sub DoSomething()
99997 On Error GoTo 99999
99998 Debug.Print 42 / 0
99999
Debug.Print Erl 'Prints 34462
End Sub
Номер строки не так актуален, как утверждение, вызвавшее ошибку, и строки нумерации быстро становятся утомительными и не совсем удобны в обслуживании.
Резюме ключевого слова
Подпрограмма обработки ошибок будет либо:
- выполняются до конца процедуры, и в этом случае выполнение возобновляется в процедуре вызова.
- или используйте ключевое слово
Resume
для возобновления выполнения внутри той же процедуры.
Ключевое слово Resume
должно использоваться только в подпрограмме обработки ошибок, потому что если VBA встречает Resume
не находясь в состоянии ошибки, возникает ошибка времени выполнения 20 «Возобновить без ошибок».
Существует несколько способов, по которым подпрограмма обработки ошибок может использовать ключевое слово Resume
:
-
Resume
используется отдельно, выполнение продолжается в инструкции, вызвавшей ошибку . Если ошибка на самом деле не обрабатывается , прежде чем делать это, то та же ошибка будет поднят снова, и выполнение может войти в бесконечный цикл. -
Resume Next
продолжает выполнение инструкции сразу после инструкции, вызвавшей ошибку. Если ошибка на самом деле не обрабатывается , прежде чем делать это, то выполнение разрешается продолжать с потенциально недействительными данными, которые могут привести к логическим ошибкам и неожиданному поведению. -
Resume [line label]
продолжает выполнение на указанной метке строки (или номер строки, если вы используете номера строк в стиле устаревшего стиля). Обычно это позволяет выполнить некоторый код очистки до того, как будет чисто выйти из процедуры, например, чтобы закрыть соединение с базой данных, прежде чем вернуться к вызывающему.
Вкл.
Сам оператор On Error
может использовать ключевое слово Resume
чтобы проинструктировать среду выполнения VBA для эффективного игнорирования всех ошибок .
Если ошибка не выполняется до этого, то выполнение разрешено продолжать с потенциально недействительными данными, что может привести к логическим ошибкам и неожиданному поведению .
Вышеупомянутый акцент не может быть особо подчеркнут. On Error Resume Next эффективно игнорирует все ошибки и выталкивает их под ковер . Программа, которая взрывается с ошибкой во время выполнения с учетом недопустимого ввода, — это более эффективная программа, чем программа, которая работает с неизвестными / непреднамеренными данными — будь то только потому, что ошибка намного легче идентифицируется. On Error Resume Next
можно легко скрыть ошибки .
Оператор On Error
является областью действия процедур — поэтому в данной процедуре обычно должен быть только один , такой оператор On Error
.
Однако иногда не удается избежать ошибки, и переключение на подпрограмму обработки ошибок только на Resume Next
просто не кажется правильным. В этом конкретном случае утверждение с известным до невозможности может быть обернуто между двумя On Error
:
On Error Resume Next
[possibly-failing statement]
Err.Clear 'resets current error
On Error GoTo 0
Команда On Error GoTo 0
сбрасывает обработку ошибок в текущей процедуре, так что любая дополнительная инструкция, вызывающая ошибку времени выполнения , будет необработанной внутри этой процедуры и вместо этого будет переходить в стек вызовов до тех пор, пока она не будет захвачена активным обработчиком ошибок. Если в стеке вызовов нет активного обработчика ошибок, он будет рассматриваться как необработанное исключение.
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
Пользовательские ошибки
Часто при написании специализированного класса вы хотите, чтобы он поднимал свои собственные конкретные ошибки, и вам понадобится чистый способ для кода пользователя / вызова для обработки этих пользовательских ошибок. Оптимальным способом достижения этого является определение специального типа Enum
:
Option Explicit
Public Enum FoobarError
Err_FooWasNotBarred = vbObjectError + 1024
Err_BarNotInitialized
Err_SomethingElseHappened
End Enum
Используя встроенную константу vbObjectError
пользовательские коды ошибок не перекрываются с зарезервированными / существующими кодами ошибок. Необходимо явно указать только первое значение перечисления, поскольку базовое значение каждого члена Enum
1
больше, чем предыдущий элемент, поэтому базовое значение Err_BarNotInitialized
неявно является vbObjectError + 1025
.
Повышение собственных ошибок времени выполнения
Ошибка выполнения может быть повышена с Err.Raise
оператора Err.Raise
, поэтому пользовательская ошибка Err_FooWasNotBarred
может быть повышена следующим образом:
Err.Raise Err_FooWasNotBarred
Метод Err.Raise
также может принимать пользовательские параметры Description
и Source
— по этой причине рекомендуется также определять константы для хранения каждого пользовательского описания ошибки:
Private Const Msg_FooWasNotBarred As String = "The foo was not barred."
Private Const Msg_BarNotInitialized As String = "The bar was not initialized."
А затем создайте выделенный частный метод для повышения каждой ошибки:
Private Sub OnFooWasNotBarredError(ByVal source As String)
Err.Raise Err_FooWasNotBarred, source, Msg_FooWasNotBarred
End Sub
Private Sub OnBarNotInitializedError(ByVal source As String)
Err.Raise Err_BarNotInitialized, source, Msg_BarNotInitialized
End Sub
После этого реализация класса может просто вызвать эти специализированные процедуры для повышения ошибки:
Public Sub DoSomething()
'raises the custom 'BarNotInitialized' error with "DoSomething" as the source:
If Me.Bar Is Nothing Then OnBarNotInitializedError "DoSomething"
'...
End Sub
Клиентский код может обрабатывать Err_BarNotInitialized
как и любую другую ошибку, внутри своей собственной подпрограммы обработки ошибок.
Примечание: наследие Error
ключевое слово также может быть использован вместо Err.Raise
, но это устаревшее / осуждается.
# Avoiding error conditions
When a runtime error occurs, good code should handle it. The best error handling strategy is to write code that checks for error conditions and simply avoids executing code that results in a runtime error.
One key element in reducing runtime errors, is writing small procedures that do one thing. The fewer reasons procedures have to fail, the easier the code as a whole is to debug.
Avoiding runtime error 91 — Object or With block variable not set:
This error will be raised when an object is used before its reference is assigned. One might have a procedure that receives an object parameter:
If target
isn’t assigned a reference, the above code will raise an error that is easily avoided by checking if the object contains an actual object reference:
If target
isn’t assigned a reference, then the unassigned reference is never used, and no error occurs.
This way of early-exiting a procedure when one or more parameter isn’t valid, is called a guard clause.
Avoiding runtime error 9 — Subscript out of range:
This error is raised when an array is accessed outside of its boundaries.
Given an index greater than the number of worksheets in the ActiveWorkbook
, the above code will raise a runtime error. A simple guard clause can avoid that:
Most runtime errors can be avoided by carefully verifying the values we’re using before we use them, and branching on another execution path accordingly using a simple If
statement — in guard clauses that makes no assumptions and validates a procedure’s parameters, or even in the body of larger procedures.
# Custom Errors
Often when writing a specialized class, you’ll want it to raise its own specific errors, and you’ll want a clean way for user/calling code to handle these custom errors. A neat way to achieve this is by defining a dedicated Enum
type:
Using the vbObjectError
built-in constant ensures the custom error codes don’t overlap with reserved/existing error codes. Only the first enum value needs to be explicitly specified, for the underlying value of each Enum
member is 1
greater than the previous member, so the underlying value of Err_BarNotInitialized
is implicitly vbObjectError + 1025
.
# Raising your own runtime errors
A runtime error can be raised using the Err.Raise
statement, so the custom Err_FooWasNotBarred
error can be raised as follows:
The Err.Raise
method can also take custom Description
and Source
parameters — for this reason it’s a good idea to also define constants to hold each custom error’s description:
And then create a dedicated private method to raise each error:
The class’ implementation can then simply call these specialized procedures to raise the error:
The client code can then handle Err_BarNotInitialized
as it would any other error, inside its own error-handling subroutine.
Note: the legacy Error
keyword can also be used in place of Err.Raise
, but it’s obsolete/deprecated.
# Resume keyword
An error-handling subroutine will either:
- run to the end of the procedure, in which case execution resumes in the calling procedure.
- or, use the
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.
# On Error Resume Next
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:
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.
# On Error statement
Even with guard clauses, one cannot realistically always account for all possible error conditions that could be raised in the body of a procedure. The On Error GoTo
statement instructs VBA to jump to a line label and enter «error handling mode» whenever an unexpected error occurs at runtime. After handling an error, code can resume back into «normal» execution using the Resume
keyword.
Line labels denote subroutines: because subroutines originate from legacy BASIC code and uses GoTo
and GoSub
jumps and Return
statements to jump back to the «main» routine, it’s fairly easy to write hard-to-follow spaghetti code if things aren’t rigorously structured. For this reason, it’s best that:
- a procedure has one and only one error-handling subroutine
- the error-handling subroutine only ever runs in an error state
This means a procedure that handles its errors, should be structured like this:
# Error Handling Strategies
Sometimes you want to handle different errors with different actions. In that case you will inspect the global Err
object, which will contain information about the error that was raised — and act accordingly:
As a general guideline, consider turning on the error handling for entire subroutine or function, and handle all the errors that may occur within its scope. If you need to only handle errors in the small section section of the code — turn error handling on and off a the same level:
# Line numbers
VBA supports legacy-style (e.g. QBASIC) line numbers. The Erl
hidden property can be used to identify the line number that raised the last error. If you’re not using line numbers, Erl
will only ever return 0.
If you are using line numbers, but not consistently, then Erl
will return the last line number before the instruction that raised the error.
Keep in mind that Erl
also only has Integer
precision, and will silently overflow. This means that line numbers outside of the integer range (opens new window) will give incorrect results:
The line number isn’t quite as relevant as the statement that caused the error, and numbering lines quickly becomes tedious and not quite maintenance-friendly.