Error Checking

Obviously, my intent wasn't clear. I was commenting on an omission that I felt left something unclear in the article referenced by @Nautical Gent in his post #47 of this thread.

@Pat Hartman - your suggested usage of Return (Next or a declared statement label) is absolutely correct. No issues there.

@isladogs - yes, true. Allen didn't use GoTo in his code - as well he should not have. There is a danger in using GOTO X in an error handler IF you make the mistake of using it as though it meant the same thing as RESUME X. That is because GOTO X doesn't clear the error context whereas RESUME X does.

@Isaac - Since Access is single-threaded, the only error that CAN occur at that point would be in the error routine itself. I will answer the question later about what happens when an error occurs in an error handler.

You can allow an exit handler to fall into an END SUB and it will be OK because Access tests for stacked context. However, you need to realize where you are when an error occurs and falls through to the END SUB. You have exited the subroutine when that happens. As for example, Pat's idea of using RESUME SUB_EXIT_POINT or whatever label floats your boat.

Suppose you have Sub A which declares a handler via On Error GoTo A_Handler.
In the course of coding Sub A, you call separately declared Sub B which does NOT declare a handler.
In the course of coding Sub B, you call separately declared Sub C which does NOT declare a handler.
Now it turns out that you have a condition that will trigger a run-time error in Sub C. Where will the trap occur?

The answer is A_Handler takes C's trap.


(Read the "Remarks" section relating to active vs. inactive error handlers.)

OK, Isaac's question: Let's say that above, Sub C actually DOES have an error handler, call it C_Handler, but it is faulty AND gets called due to an error in the "normal" part of Sub C. If an error handler gets activated and there is an error in the code,...

In the three layers I named above, C cannot take the trap because its error handler is already activated. B cannot take the trap because no handler was declared. So I believe in the case of Isaac's question, A_Handler would take that trap.

Finally, again suppose that Sub C gets called, trips over itself such that the error handler C_Handler gets called; but C_Handler has an error, too, and eventually the error "bubbles up" such that A_Handler takes the error. A_Handler finishes with a RESUME NEXT. In this case, which line of code is executed next?

Answer: The line following the call (in the context of Sub A) to Sub B.

Sub C and its instantiation vanished when C_Handler failed and the error got passed up to B - which ALSO failed because the error had to be passed back up another layer - to A_Handler. From A_Handler (which is part of Sub A) you cannot return to any label in B or C via a RESUME SOME_LABEL - because they are no longer in scope. The only thing in scope at that point is Sub A.


The next reference emphasizes the point that the "current" error handler doesn't necessarily have to be in the same routine in which the error occurred. It's an Excel source but the VBA advice is spot-on.


My point, I guess, was that I didn't think the article brought up as much as I thought it should. You guys know that sometimes I get a wild hair somewhere. This post resulted from scratching where that wild hair itched.
 
@The_Doc_Man
the only question I was asking was what Dave meant. I was just pointing out that you can have additional errors occur inside the error handling...that's all
 
Thanks Doc but my reply was also directed at Dave - not at you.
Its not at all clear what Dave was referring to.

Also, although I've NEVER known it happen, its easy to determine what happens if errors occur inside an error handler.
Just add err.raise statements like this e.g. to a button click event ...

Code:
Private Sub cmdErrorTest_Click()

On Error GoTo Err_Handler

'code here
    MsgBox "Click OK to raise error 11 in the main code"
   Err.Raise 11

Exit_Handler:
    MsgBox "Click OK to raise error 94 in the Exit Handler section"
    Err.Raise 94
    Exit Sub

Err_Handler:
    MsgBox "Error " & Err.Number & " in cmdErrorTest_Click procedure : " & vbCrLf & _
        Err.Description, vbCritical, "Program error"
    MsgBox "Click OK to raise error 7 in the Err Handler section"
    Err.Raise 7
    Resume Exit_Handler

End Sub

If anyone wants to try it out, see whether you can predict what will happen first.
Will all three errors get triggered in turn? If not, then what?

For info, don't worry...an infinite loop doesn't occur
 
Last edited:
Did you mean, errors that occur inside an error handler are automatically ignored until you resume? I think you must have meant something else because that is not the case, you will just get an unhandled error.

Or did you just mean that Resume clears the err object and until it's explicitly cleared or Resume then ... ?

Yes - my bad.

especially for @Isaac @isladogs @The_Doc_Man

[I have edited this first para slightly now, and added an extra note below]
That's what I sort of meant. A second error that occurs within the error handler is ignored (ie - does not trigger the error handler again) until after you resume after the error, and this may allow programme errors to be missed. I also didn't mean necessarily within the error handler - I meant that until you issue the resume the error handler is still active, and a second error wouldn't be handled. Without testing I am not sure that you do always get an unhandled error. I thought that in the past, I had data errors that were not picked up because of this, but I could be wrong. See my edit below. Therefore you don't want any code within the error handler that might throw another error. Using goto rather resume is a bad habit, as it can be the cause of unhandled errors. I am pretty sure that ending the sub also exits the error handler, but I prefer to explicitly resume, and to keep the error handlers as short as possible.

[edit - I see what you mean now. I just tried your code and a second error within the error handler did produce an unhandled error. Maybe there are some errors that wouldn't get flagged as unhandled errors. As I say, I thought I had experienced issues caused by such circumstances, but I am always careful to resume after any error, and I am quite likely getting confused. Alternatively, maybe it was just code not working correctly because of accidentally using a Goto instead of a Resume, and then finding that a different on error trap did not work as expected]
 
Last edited:
Hi folks,

These are the last few lines of my function.

You can see On Error Resume Next in them.

This doesn't work - if "permission denied" to delete what I am calling the 'log file', it raises a Debug error!
(You can see what I am doing - I have boolean variables, starting with bl, to indicate whether a given file still exists - and then in my error handler, I'm deleting them if they exist - a common practice which has worked well for me for a long time - but now I am realizing that the On Error Resume Next portion of it actually never worked apparently, because while inside the error handler, the On Error Resume Next is ignored.

Thoughts?

Code:
Exit Function
errhandler:
If blBatExists = True Then
    Kill strBatPath
End If
If blScriptExists = True Then
    Kill strScriptPath
End If
If blLogExists = True Then
    On Error Resume Next
    Kill strDownloadFolderPath & "\WinSCP.log"
End If
GetSourceFile_Method_One = "Error: " & Err.Description
End Function

The log file is the only thing I can't be sure if it will be delete-able, because, it's outside the control of my program.
 
Last edited:
If I understand you correctly, all you would have to do is trap for that particular err.Number and simply do nothing and resume where you left off...?
 
If I understand you correctly, all you would have to do is trap for that particular err.Number and simply do nothing and resume where you left off...?

I cannot tell for sure - you may not be understanding (or maybe it's me who doesn't understand what you're suggesting).

Remember, we're already in the error handler, because of some (probably) different error.

So I may have created my code and made some dumb mistake. I get something like "object not set" or whatever.
At that time, my error handler is hit. Inside it, I want to just 'clean up' some other (unrelated to the error) things.
Particularly, I want to kill the log file if it exists. But, I'd like to effective ignore any additional error that occurs while trying to delete it, just give up deleting it at that point.

I think what you're suggesting might be something like this:

Code:
Function Foo()
On Error GoTo Errhandler
........code runs, does whatever

ExitFunction:
Exit Function
Errhandler:
if blLogExists then
    On Error Resume Next
    Now try to kill log file
    If err.number=9 then 'permission denied
         Resume ExitFunction
    End if
End Function

The problem is that structure would suffer from the same malady as the first one - the On Error Resume Next (which is what you'd use to allow an error to occur but not hard stop, then check for Err.Number) is totally ignored in the first place.

In both cases, the code never gets past the line that tries to delete the log file.

If I've misunderstood, please post a suggested code structure.
 
I am not 100% sure about this, but if I correctly recall the rules of error handling, this sequence cannot work.

Code:
Errhandler:
if blLogExists then
    On Error Resume Next
    Now try to kill log file
    If err.number=9 then 'permission denied
         Resume ExitFunction
    End if

The part that bothers me is the ON ERROR RESUME NEXT within the error handler. The catch is that error handling routines cannot see errors in themselves. More specifically, an error trap goes to the first inactive but enabled error handler. In order to execute that ON ERROR RESUME NEXT in that position, you would have to already be in an active error handler. And that IS an executable statement, not a compile-time statement, because you can have sequences that do ON ERROR GOTO 0 followed by ON ERROR RESUME NEXT or ON ERROR GOTO NEW_HANDLER within a routine and they each take effect in proper sequence.

The other problem is this, and it isn't a terrible problem, its more of a "moot point" problem. In that error handler, you will always do nothing. If the flag is TRUE (blLogExists) then (from your comments) you will try to kill the log file. If you get the "Permission Denied" error then you exit the function at its "normal" exit point. But if the error is NOT #9, you fall through to an END FUNCTION - which is the other legal way to exit a handler. And if theblLogExists is FALSE then you also fall through to the END FUNCTION. In any case you do nothing (unless you put code in to delete the file and it actually DOES get deleted.) But as I pointed out above, if there IS an error, this handler will NOT perform the ON ERROR RESUME NEXT.

Then there is questionable wisdom of actually deleting a file from an Exit Handler. Recommended "best practices" for error handlers are to leave behind a trace of their findings, like setting a flag or something, that would then be detected by the main-line event code that had declared the handler.

You DO NOT WANT to slow down your code by engaging in a file operation from within an exit handler. You COULD, if you really wanted, test variables to decide whether some external test has verified your ability to take the desired action. But error handlers are like interrupt routines. Nothing in your code can interrupt an error handler so you are in that context until you RESUME out of the handler OR the first error that occurs inside that handler WILL leave that handler in the dust, since errors cannot interrupt active handlers. They can only stop them.
 
@Isaac

out of interest,
Why are you killing all these files inside the error handler?
What error makes the code jump to the error handler?
Kill might error on any of the deletes, so why just try to error protect the third delete?

Code:
errhandler:
If blBatExists = True Then
    Kill strBatPath
End If
If blScriptExists = True Then
    Kill strScriptPath
End If
If blLogExists = True Then
    On Error Resume Next
    Kill strDownloadFolderPath & "\WinSCP.log"
End If
GetSourceFile_Method_One = "Error: " & Err.Description
End Function
 
If I've misunderstood, please post a suggested code structure.
No sir, you understood me completely. I cannot offer anything new that hasn't ben offered and, frankly, my understanding of what goes on after an error is raised and in the process of being handled, leaves a LOT to be desired.

The only thing I might consider if it were my app, would be to call a separate sub that would handle the file deletion, either successfully or unsuccessfully and then resume.

I am interested in seeing your answers to Dave's questions.
 

Users who are viewing this thread

Back
Top Bottom