I have a question about the correct way to handle errors in VBA in Excel. If a specific error, say xxxxxxx, occurs, then a MsgBox should be displayed. If another error occurs the standard run-time error handler should pop up. How can this be accomplished? Here is the example code:
On Error Resume Next
'Line of code that causes an error here.
If Err.Number = xxxxxxx Then
MsgBox "Specific error message."
ElseIf Err.Number = 0 Then
Do nothing
Else 'Some error other than xxxxxxx.
'This is the problem. Here I would like to display standard run-time error
'handler without causing the error again.
End If
On Error GoTo 0
You can get a message box that looks very much like the standard error message by putting this into your "Else" block:
MsgBox "Run-time error '" & Err.Number & "':" & _
vbNewLine & vbNewLine & _
Error(Err.Number), vbExclamation + vbOKOnly, _
"YourProjectNameHere"
But this is just a facsimile. It's not the actual error message dialog that VB6 puts up; it's just formatted to look like it. Error handling is still disabled by the "On Error Resume Next" statement at this point.
But if you really, really want to invoke the standard error handling code, you can put this in the "Else" block:
Dim SaveError As Long
SaveError = Err.Number
On Error Goto 0
Error (SaveError)
This code saves the error number, re-enables error handling, and then re-raises the error. You invoke the VB runtime's true error handling machinery this way. But beware: if this error isn't caught with an active error handler somewhere higher in the call chain, it will terminate your program after the user clicks on the "OK" button.
Note that you'll also lose the ability to get the actual line number where the error occurs using" Erl" in that error handler because you are re-generating the runtime error with the "Error (SaveError)" statement. But that probably won't matter because most VB code doesn't actually use any line numbers, so Erl just returns 0 anyway.
Replace On Error Resume Next with
On Error Goto SomePlaceInCodeToHandleErrors
SomePlaceInCodeToHandleErrors:
If Err.Number = XXXX Then
MSGBOX "Message"
End If
Check out this Stack Overflow thread for some more information and example code.
In your VBA options, select "Break on unhandled errors".
To enable handling use on error goto SomeLabel or on error resume next.
To stop error handling use on error goto 0.
Your question is contradictory in this context. If you enable error handling, well, you disable the standard error handling.
As DaMartyr suggests, you can still use something like msgbox err.description.
So to follow up on JeffK's new suggestion the code below seems to work fine with VBA, and what's more I can't see the danger in using it. To terminate Excel is critical as that could lose a lot of work, but since the code always checks that the error is there how could that happen?
Thank you JeffK for this intriguing idea.
Dim savedNumber As Long
On Error Resume Next
'Line of code that causes an error.
If Err.Number = XXXXXXX Then
'Specific error message.
ElseIf Err.Number <> 0 Then
savedNumber = Err.Number
On Error GoTo 0
Error savedNumber
End If
Err.Clear
On Error GoTo 0
Related
This is a very fussy question: I am inserting an Error Handler in a For To loop in Excel VBA; I want the content of the loop indented, such that:
For i = 0 to n
On Error GoTo ErrorHandler:
'~~> code here
ErrorHandler:
'~~> code here
Resume NextLoop
NextLoop:
Next
However, Excel VBA automatically cancels indentation of Error Handlers:
For i = 0 to n
On Error GoTo ErrorHandler:
'~~> code here
ErrorHandler:
'~~> code here
Resume NextLoop
NextLoop:
Next
I have tried to unselect option "Auto Indent" in "Tools" > "Options" > "Editor" but this hasn't worked.
How can I avoid this?
Edit There was a careless mistake in the original code. Thank you user2426679 for giving me the opportunity to fix it.
Original post
Code that uses GoTo Label can be a nightmare to understand and get error free. The only situation I know off in which GoTo Label might be appropriate is a fatal error exit where there is no intention to return. Jumping out of an error and trying to jump back is very difficult to get right and very difficult to understand when you return to it in a few months.
Is there more than one statement in your code that can throw an error? If so, how does the error handler know which error it is handling?
I favour:
On Error Resume Next ' Suspend normal error handling
Statement that might throw an error
On Error GoTo 0 ' Restore normal error handling
If Err.Number <> 0 then
' Code to handle error
End If
The value of Err.Number and Err.Description will tell what the error is and allow to write specific error handling code.
Some argue that taking error handling out of the main code keeps the main code clean. There is some merit in this argument. If there are dozens of potential errors, the analysis can become complicated and make the normal path difficult to isolate. But, in my experience, this is very unusual. Perhaps, you have a list of files some of which might not open. There are lots of reasons why a file does open but your code can do nothing about them. All it can do is display Err.Description and move onto the next file.
New text and code
Apart from the mistake in the code there is nothing in my original post that I now consider incorrect. However, I do not think the original post was as complete as it should be.
If you search for “VBA Err.Number” you will find sites that list VBA’s error handling codes. Since these sites come and go, I will not recommend my favourite. However, I try to generate errors to see what happens. Consider this code:
Option Explicit
Sub DemoErrorHandling()
Dim ErrDesc As String
Dim ErrNum As Long
Dim FileNum As Long
Dim PathFile As Variant
FileNum = FreeFile
For Each PathFile In Array("", "X:", "C:\Program Files\Common Files\Intel\" & _
"WirelessCommon\libeay32.dll")
On Error Resume Next
Open PathFile For Input As FileNum
ErrNum = Err.Number
ErrDesc = Err.Description
Close FileNum
On Error GoTo 0
Debug.Print """" & PathFile & """ gives error:"
Debug.Print " A " & Err.Number & " " & Err.Description
Debug.Print " B " & ErrNum & " " & ErrDesc
Next
End Sub
Which, on my system, outputs:
"" gives error:
A 0
B 75 Path/File access error
"X:" gives error:
A 0
B 76 Path not found
"C:\Program Files\Common Files\Intel\WirelessCommon\libeay32.dll" gives error:
A 0
B 0
Note, as user2426679 pointed out, On Error GoTo 0has cleared Err.Number and Err.Description. Only by saving these values in variables are they available for testing. Note, attempting to open an empty file name and a non-existent disc give different errors.
My code demonstrates that you can loop trying different files until one opens successfully. You could keep asking the user for a file until one opened without an error.
Following on from my Connections query, I now want to capture any connections that cannot be reached and throw an error message to state that the relevant connection cannot be reached.
This is the code I have so far, however, I'm not sure if it's capturing any errors:
Private Sub btnRefreshConns_Click()
On Error GoTo ErrorHandler
Dim cn As WorkbookConnection
For Each cn In ActiveWorkbook.Connections
cn.Refresh
Next
Exit Sub
ErrorHandler:
MsgBox "A connection could not be reached" & cn.Name & ": " & cn.Description
End Sub
Could someone please assist me or let me know if this code would work?
Yes, the sample will catch connection errors. Change the MsgBox line to this to fix the reporting:
MsgBox "A connection could not be reached: " & Err.Number & ": " & Err.Description
Err has info about the latest error.
There's only one catch: all errors will be caught, not just connection errors. That is why I suggest not referring to cn in your error handler: you don't know what state it will be in if an unrelated error happens (say, out of memory - which can happen!). A better approach is to wrap just the code of interest. Inside your For loop:
On Error GoTo ErrorHandler
cn.Refresh
On Error GoTo 0 ' Reset default error handling
Edit: The On Error GoTo 0 unhooks your ErrorHandler and returns to the default error-handling mode, which is to show the error dialog box. The 0 is just a magic number that VBA is programmed to recognize for this purpose. See more details and explanation at Chip Pearson's page on the subject, which is my personal go-to reference.
I have never used On Error GoTo -1, but this answer suggests I'm not missing anything :) . It is apparently used to continue executing normal code after ErrorHandler, but I have always used Resume for that and had no problems.
Caveat: never never never forget the Exit Sub before ErrorHandler. I did once and got stuck in an infinite error loop I could only escape by killing Excel. Resume causes an error if you run it when an error isn't actually being handled and that error threw to the error handler having the Resume... yeah. Ugly.
I'm Writing a macro program, in that I need to show custom error message if error occurs, I'm facing a problem here. Error handing is working correctly. but the codes in error handling section are executing even though the error not occurred
On Error GoTo ErrorHandling
Source_File_Path = "G:\" & Source_File_name & ".csv"
Open Source_File_Path For Input As #1
On Error GoTo 0
.
.
.
ErrorHandling:
Worksheets("REPORT_VIEW").Activate
MsgBox "FILE NOT FOUND"
I'm seeing the "FILE NOT FOUND" Error on every time.
Help Me., Cheers...
You need to add an Exit sub statement (or Exit Function if you code is from a function). for instance:
sub MySub()
On Error GoTo ErrorHandling
Source_File_Path = "G:\" & Source_File_name & ".csv"
Open Source_File_Path For Input As #1
On Error GoTo 0
.
.
Exit sub
ErrorHandling:
Worksheets("REPORT_VIEW").Activate
MsgBox "FILE NOT FOUND"
end sub
I have written an excel VBA script which refers to another open excel document for some of it's data. Recently it has come to my attention that if this secondary document is closed unexpectedly by the user, the primary script ceases to work. Obviously, I need to check to be sure it is open before I search it.
Below is the code I came up with to verify that the workbook is open. If it is, I format it. If it isn't, I open it (which triggers it's own formatting). The problem comes in because my error handler catches the "Object required" error number 424. I try to take care of that by instructing it to just resume next when this happens. Unfortunately it seems to want to pick case else rather than case 424 and stops the script.
On Error GoTo searchGridsError
GridName = Workbooks(SALTname).Sheets(2).Range("B3").value
If Verify.FirstOption.value = True Then
Set Verify.groupGrid = Workbooks(GridName)
If Verify.groupGrid Is Nothing Then
Verify.checkForGrids
Else
formatWorkbook
End If
End If
Below is my error handler:
searchGridsError:
Select Case Err
Case 18
Verify.clearData
Exit Function
Case 424
Resume Next
Case Else
MsgBox "An error has occurred while searching the customer number grid. Please try again or search manually."
Module1.ReportError Err.Number, Erl, Err.Description, "searchGrids", Verify.Address1Box & "," & Verify.Address2Box & "," & Verify.CityBox & "," & Verify.StateBox & "," & Verify.ZipBox & "," & Verify.ContractBox & "," & Verify.PBPBox & "," & Verify.CountyBox
Verify.clearData
Exit Function
End Select
End Function
Does anyone have any ideas about why this is happening? It has to be in the error handler but I have seen many, many examples that look just like mine.
As guitarthrower stated in the comments, simply putting Resume Next in your error handling does not resume your macro back where the error occurred. To do that you would need to put another placeholder after your On Error GoTo searchGridsError line like RestartHere: where you want to jump back to and then replace Resume Next with:
On Error Resume Next
GoTo RestartHere
However, this will bypass your error handling once Error 424 is encountered, so you should be wary of how it is used.
Probably a better solution would be to put your error handling right in your code where you expect the error to occur. You can leave your code mostly as-is. However, right before the line that is throwing Error 424, you add On Error Resume Next. Then after the line in question, you add the following:
If Err.Number = 424 Then
Err.Clear
End If
On Error GoTo searchGridsError
I am getting a type mismatch error on the line of code below. It is inside a loop, and the error doesn't occur until the first iteration where .Cells(rowStart + i, ISO_revs_col).Value is a string. It makes sense that this would cause an error, but I would expect the .IfError function to just return the "0" string. If anyone can tell me why I am getting an error instead of "0" I would appreciate it.
Debug.Print Application.WorksheetFunction.IfError(CLng(.Cells(rowStart + i, _
ISO_revs_col).Value), "0")
Thanks in advance.
IFERROR is a worksheet function, and will detect worksheet errors. The following error types are evaluated: #N/A, #VALUE!, #REF!, #DIV/0!, #NUM!, #NAME?, or #NULL!.
Type mismatch (runtime error 13) is a VBA error, not a worksheet error.
To handle VBA errors, you need to use the VBA error handling routines. So something like:
EDIT: to trigger on other errors:
On Error Resume Next
'your looping routine start
x = CLng(.Cells(rowStart + i, ISO_revs_col).Value)
select case err.number
case 13
x=0
err.clear
case <> 0
msgbox "Error " & err.number & vbTab & err.description
end select
debug.print x
'your looping routine end
on error goto 0
The above won't tell you where the error occurred, so you might want to just wrap the single line as:
on error resume next
x = CLng(.Cells(rowStart + i, ISO_revs_col).Value)
if err.number = 13 then x = 0
on error goto 0