I've been trying to make this work and I just can't seem to figure it out. I have this test piece of code that I got from here.
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
This is supposed to help me understand error management but when it's ran I get a: Compile Error: Expected Function or Variable on err.Number; it specifically highlights err.
Any help would be appreciated.
One minor thing I noticed in your code is the "err" is lower case. When I pasted your code into a blank workbook and ran it, Excel automatically capitalized "Err" in the code. As people mentioned in the comments, this probably means that you have something else open which has a conflicting definition of "err" in it. Try running your code without any other files open.
Related
This question already has answers here:
How to check which line of VBA code is causing errors
(3 answers)
Closed 3 months ago.
Question:
In VBA, is there any way to execute some clean up code after an error is raised without either A) losing the detail of the native error messages by manually raising the error, or B) inserting & maintaining line numbers throughout my code? Edit for clarification: The detail being lost is the 'debug' button on the native error message which then highlights the line causing the error.
More Background/Info:
I want to change the calculation mode to manual at the start, but I want to ensure it's changed back before the code exits. This is fine if there's no error, but the only way I can think to ensure it's raised even if an error is encountered is to change the exception handler to something like On Error Resume Next, ensure the calculation mode is restored, then manually raise the error. But doing this loses details like where the error occurred; making it more difficult to resolve issues.
The only 'solution' I've been able to find is to manually (or using a tool) add line numbers which can then be used in the manually raised error; but this seems a pain to maintain and (imo) makes the code a bit messy.
If these truly are the only two options (and my fruitless searching seems to suggest that's the case; but sorry if this has been answered somewhere and I just failed to find it) then so be it; I'll have to opt for one of them. But I just wanted to see if anyone knows of another option?
Dummy Code:
(Just a quick mock-up of what it might look like with the 'raise the error manually and lose the details' method). Edit for clarification: The error in the below code is simple just to have something throwing an error; here it would be obvious where the error was, but in the 'real' problem it might not be obvious where the error was triggered (which is where the debug option on the native error message comes in handy).
Sub Example()
Dim OrigCalcMode as XlCalculation
OrigCalcMode = Application.Calculation
Application.Calculation = xlCalculationManual
On Error Resume Next
' Main code would go here, but to simply induce an error...
Dim Val as Integer
Val = 1 / 0
If Err.Number <> 0 Then
MsgBox ("Error Number: " & Err.Number & vbCrLf & vbCrLf & _
"Error Description: " & Err.Description)
Err.Clear
End If
On Error GoTo 0
Application.Calculation = OrigCalcMode
End Sub
Your example is maybe a little too simple - typically there's the consideration of (eg) how to handle errors in calling code, and how to decide if an error is "fatal" (all subsequent steps should be aborted) or recoverable.
A typical approach might be something like:
Sub Example()
Dim OrigCalcMode As XlCalculation
OrigCalcMode = Application.Calculation
Application.Calculation = xlCalculationManual
On Error GoTo haveError
' Main code would go here, but to simply induce an error...
Dim Val As Integer
Val = 1 / 0
cleanExit:
Application.Calculation = OrigCalcMode 'make sure to reset this
Exit Sub 'don't run into the error handler
haveError:
MsgBox "Error Number: " & Err.Number & vbCrLf & vbCrLf & _
"Error Description: " & Err.Description
'<Make any decisions about what to do with this specific error>
Resume cleanExit 'Resume clears the Err object
End Sub
This question already has answers here:
Why VBA goes to error handling code when there is no error?
(5 answers)
Closed last year.
Example Code:
On Error GoTo Line3
More code
Line3:
Some code
Some code
More code
Even when there is no error, the "some code" underneath Line3 still gets run even though I don't want it to run. Otherwise when there is an error, Line3 gets run appropriately (skipping code that comes before it like it should).
Your code runs as it should. Code dealing with errors should be written outside of the main procedure, keeping in mind that your code should also try and spot potential errors and deal with them before they cause an error.
At the moment your error isn't being cleared when you jump to it, and because it's in the main body of code it's executed when your first set of More Code is finished and it reached the Line3 label.
Sub Test1()
'Ignore the error.
'MsgBox won't appear, but code won't know an error occured.
'MsgBox says all's good anyway, even though the error is still present.
Dim Rng As Range
On Error GoTo SkipLineWithError
MsgBox Rng.Address
SkipLineWithError:
MsgBox "All good, error number is " & Err.Number
End Sub
A better way is to try and catch the error before it happens:
Sub Test2()
'Checks that Rng won't throw an error if referenced.
'Code has dealt with the error and says all's good.
Dim Rng As Range
If Not Rng Is Nothing Then
MsgBox Rng.Address
Else
MsgBox "Range not set"
End If
MsgBox "All good, error number is " & Err.Number
End Sub
Sometimes, errors do occur though and they need to be dealt with properly. For this you jump out of the main procedure, deal with the error and jump back in again.
With this code notice the Exit Sub - the code between Exit Sub and End Sub is where your error handling goes. The main body of code ends when it reaches Exit Sub.
Resume tells your code where to jump back to - on its own it jumps back to the line that caused the error, Resume Next is the line after the error and Resume <label> jumps back to a label you've entered such as Resume Line3
Sub Test3()
Dim Rng As Range
On Error GoTo ErrorHandler
MsgBox Rng.Address
MsgBox "All good, error number is " & Err.Number
TidyExit:
'Close connections, general tidy up before ending procedure.
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 91 'Deal with the error if it happens.
'For this we'll give Rng a default address.
Set Rng = Sheet1.Range("A1")
Resume
Case Else
MsgBox "Error couldn't be handled... display an error message."
Resume TidyExit 'Jump to end of main body of code.
End Select
End Sub
Edit: Have updated code based on comment by #VBasic2008. Was being lazy with my first code and missed a key point.
I've barely scraped the surface here, the links below should help.
on-error-statement
vba-error-handling
Using Gotos to manage execution paths is almost always a poor design choice. You could consider the following approach that does not rely so heavily on Goto labels. It is easier to see the intended logic flow (and error handling) without having to visually parse any Goto statements.
Sub Example()
If Not TryMorecode1() Then
Somecode1
Somecode2
End If
Morecode2
End Sub
Private Function TryMorecode1() As Boolean
'catch errors locally within this function
'return False if an error is generated
End Function
Private Sub Morecode2()
End Sub
Private Sub Somecode1()
End Sub
Private Sub Somecode2()
End Sub
The code will still run, it's just a label you can point the execution to if need be.
Try this to avoid your problem but without knowing your exact requirement, you’ll likely need to tweak the code structure to suit your needs.
My suggestion would be to put Line3 at the bottom, not in the middle of the routine. That way you just do a clean up and then get out. It tends to make more sense from a readability perspective. Of course, you should only do that if it makes sense to get out after the error occurs.
On Error GoTo Line3
More code
Goto Line4
Line3:
Some code
Some code
Line4:
On Error GoTo 0
More code
The trick with GoTo statements (if you intend to use them) is to use them sparingly.
How can I get error details like line number, error message in VBA.
It displays simple message like "Compile error", but does not show detail and line number of error.
How can I get error details like line number, error message in VBA.
Compile error will not let you compile the code and will directly take you to the line which has the error. For other runtime errors, you need to add line numbers to your code and then use ERL to get the line number. For example
Option Explicit
Sub Sample()
Dim i As Long
10 On Error GoTo Whoa
20 i = "Sid"
30 Debug.Print i
Whoa:
40 MsgBox Err.Description & ". Error on line " & Erl
End Sub
Tip: I use MZ-Tools which helps in inserting/removing line numbers. I think (I am not sure) rubberduck also does that.
If your VBA code doesn't contain line numbers, then VBA can not show it.
Purpose of displaying line number is to trace and resolve an error which you can handle using:
On Error GoTo ErrHandler
And then Error Handler Block
ErrHandler:
Refer this.
Compile error is different than runtime error.
The compile error will not let the application build and run and the line of code which causes the error is highlighted. On the other hand, runtime error is when the application runs but something unexpected happens which raises an error, a division by zero for exampe.
Once you have sorted out the compile error and the app runs, you can handle rutime errors like this:
Option Explicit
Sub Something()
On Error GoTo Trap
'your code here
Leave:
On Error GoTo 0
Exit Sub
Trap:
MsgBox Err.Number & " - " & Err.Description, vbCritical
Resume Leave
End Sub
I have the followin code. But the error does not get handled
Sub Some_sub()
Some code here
On Error GoTo resumeCode
If Workbooks("Some file.xlsm").ReadOnly Then
GoTo readOnlyError
End If
resumeCode:
On Error GoTo fileNotOpen
Workbooks("Some file.xlsm").Activate
some more code here
Exit Sub
fileNotOpen:
MsgBox "Error: Claims followup.xlsm is not open." & Chr(10) & Chr(10) &
"Open the file in read/write"
Exit Sub
End Sub
When I run debug mode it shows me this line: Workbooks("Some file.xlsm").Activate in yellow. Instead of handling the error and going to the label.
Within VBA under Tools -> Options -> General Tab: Break on Unhandled Errors active.
When I have the file open it runs the code like it should. When it is closed it does not handle the error.
What am I doing wrong?
Thanks in advance for your help
That's it. As I said in the comments, when an error occurs, and you handle it, you cannot setup a new On Error mechanism until you explicitly invoke the Resume keyword in any way.
One possible way to achieve it, if you dont want to change the flow of your routine, is just to add a label before your new On Error statement and Resume on it. Like this, for example:
Sub Some_sub()
' Some code ...
On Error GoTo resumeCode
If Workbooks("Some file.xlsm").ReadOnly Then
GoTo readOnlyError
End If
' Some more code ...
resumeCode:
Resume ResumeHere ' <---------------------------------------- Invoke Resume
ResumeHere: ' <------------------------------------- Add some label
On Error GoTo fileNotOpen
Workbooks("Some file.xlsm").Activate
Exit Sub
fileNotOpen:
msgBox "Error: Claims followup.xlsm is not open." & Chr(10) & Chr(10) & "Open the file in read/write"
Exit Sub
End Sub
You should be careful though, the keyword Resume will itself raise an error if the error status is blank and it is reached from normal flow, In that case you should put the error handling sections, each apart, in the end of your routine and resume at any labels within the normal flow from there. This is generally the usual approach.
I've looked through countless examples (and there are many to be found) of how to use Ranges to accomplish a VBA user defined function/sub to copy the value of one specified cell to another. Unfortunately, no matter which I try, I am unable to avoid Error 1004 Application-defined or object-defined error. Here is the very simple test code:
Private Sub Foobar()
On Error GoTo fooErrorHandler
Dim c1 As Range
Dim c2 As Range
Set c1 = Sheets("Sheet1").Range("D2")
Set c2 = Sheets("Sheet1").Range("B3")
c2.Value = c1.Value
Exit Sub
fooErrorHandler:
MsgBox "Error Number: " & Err.Number & vbNewLine _
& "Description: " & Err.Description
End Sub
Thanks for any help/pointers!
Generally speaking you cannot use a Function to manipulate the worksheet object. It looks like you're trying to get around that by invoking a subroutine from the barfoo function call. I suspect that is the error... If you run the subroutine foobar manually (press F5 or run from the macro menu) it should execute without error.
I confirm that this implementation raises the error, and also test the manual call to foobar without error.
If you can better describe the ultimate goal, perhaps we can recommend a more reliable way to achieve it.
Modifying cells inside UDF (a function, that is used inside a cell the same way as built-in formulas) is not allowed. If you remove a call to barfoo from C1 cell, both Foobar and barfoo should work without problems.