I thought that I had a basic understanding of errors

G

Greg Maxey

Can someone help me understand why TestA works and TestB and TestC do not:

Sub TestA()
On Error Resume Next
Err.Raise 6
On Error GoTo SubErr:
Err.Raise 13
SubErr:
MsgBox "Eureka!!"
End Sub

Sub TestB()
On Error GoTo Err_Handler
Err.Raise 6
Err_Handler:
On Error GoTo SubErr:
Err.Raise 13
SubErr:
MsgBox "Eureka!!"
End Sub

Sub TestC()
On Error GoTo Err_Handler
Err.Raise 6
Err_Handler:
On Error Resume Next
Err.Raise 13
MsgBox "Eureka!!"
End Sub

In TestB and TestC, I have tried about every combination of GoTo, Resume, Err.Clear, that I can think of. I don't understand why the code isn't handling the second error. thanks.
 
J

Jezebel

Not sure quite what you mean by 'working' in respect of TestA -- it ignores the first error, and jumps to SubErr for the second.

But the big issue, is that none of your error-handlers actually 'handles' the error. An error is handled when the function exits or you execute a resume or resume [label] instruction. Until you do that, the code is still running within the context of the original-handler, and any further errors are passed 'up the line' to an error-handler in the calling function, if there is one. So a) the error-handler can't deal with errors within the error-handler itself, and b) you can't issue a new 'on error goto ...' within the context of the error-handling code. Try this --

Sub TestA()
On Error GoTo SubErr:
TestB

SubErr:
MsgBox "Error in Test A"
End Sub

Sub TestB()
On Error GoTo Err_Handler
Err.Raise 6

Err_Handler:
On Error GoTo Err_Handler:
MsgBox "Error in TestB"
Err.Raise 13

End Sub


The moral is, don't try to do clever things in the error-handling code: just handle the error and resume, either back to the code or to the exit point.




Can someone help me understand why TestA works and TestB and TestC do not:

Sub TestA()
On Error Resume Next
Err.Raise 6
On Error GoTo SubErr:
Err.Raise 13
SubErr:
MsgBox "Eureka!!"
End Sub

Sub TestB()
On Error GoTo Err_Handler
Err.Raise 6
Err_Handler:
On Error GoTo SubErr:
Err.Raise 13
SubErr:
MsgBox "Eureka!!"
End Sub

Sub TestC()
On Error GoTo Err_Handler
Err.Raise 6
Err_Handler:
On Error Resume Next
Err.Raise 13
MsgBox "Eureka!!"
End Sub

In TestB and TestC, I have tried about every combination of GoTo, Resume, Err.Clear, that I can think of. I don't understand why the code isn't handling the second error. thanks.
 
J

Jay Freedman

Hi Greg,

I'll quote the Remarks section of the help topic for the On Error
statement:

"If an error occurs while an error handler is active (between the
occurrence of the error and a Resume, Exit Sub, Exit Function, or Exit
Property statement), the current procedure's error handler can't
handle the error. Control returns to the calling procedure. If the
calling procedure has an enabled error handler, it is activated to
handle the error. If the calling procedure's error handler is also
active, control passes back through previous calling procedures until
an enabled, but inactive, error handler is found. If no inactive,
enabled error handler is found, the error is fatal at the point at
which it actually occurred."

Looking at your examples, TestA only has one handler and it's
triggered by the Err.Raise 13. That is, the Resume Next doesn't count
as an "active error handler". In TestB and TestC, you're trying to
catch an error while you're already inside an active error handler,
and that isn't allowed.

To see what the help is talking about wrt a calling procedure, try
single-stepping with F8 through this code, starting in TestD:

Sub TestD()
On Error GoTo Err_HandlerD
Call TestE
Exit Sub

Err_HandlerD:
MsgBox "D: Eureka!! (" & Err.Number & ")"
End Sub
'~~~~~~~~~~~~
Sub TestE()
On Error GoTo Err_HandlerE
Err.Raise 6
Exit Sub

Err_HandlerE:
On Error GoTo SubErr
Err.Raise 13
Exit Sub

SubErr:
MsgBox "E: Eureka (" & Err.Number & ")!!"
End Sub

At a language-design level, I think this restriction was put into VBA
to avoid having to deal with some nasty issues. You can easily get
into infinite loops when you allow error-handling that itself can
cause errors. OTOH, there are legitimate circumstances where you want
to do something of this sort -- for example, if an error occurs and
you want to log it, but you get an error from the OS when you try to
open the log file. There are ways to handle that with only On Error
Resume Next.

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the
newsgroup so all may benefit.
 
G

Greg Maxey

Thanks Gents,

I did reply last night, but see this morning that it didn't transmit.
I have had a few error messages the past two days using OE that
newsgroups coudn't be resolved?

Anyway, thanks for both replies. Jezebel, by working I just meant the
code would run without generating a runtime error. With your reply and
Jay's I see now why it would and the others wouldn't. It was a poor
example.

The basic problem was this. I wanted an error handler that when an
error was generated that it would simply ignore it an go on to save the
document. I was working with TestA below which worked OK except when
the user canceled or "X" out of the SaveAs Dialog. It would then throw
and error while in the error handler.

Sub TestA()
On Error GoTo Err_Handler
MsgBox ActiveDocument.Bookmarks(1).Range.Text
'Other Stuff
Exit Sub
Err_Handler:
ActiveDocument.Save
End Sub

I can work throug that issue using this construction. Do either of you
see problems with this method? Thanks.

Sub TestB()
On Error GoTo Err_Handler
MsgBox ActiveDocument.Bookmarks(1).Range.Text
'Other Stuff
Exit Sub
Err_ReEntry:
On Error Resume Next
ActiveDocument.Save
Exit Sub
Err_Handler:
Resume Err_ReEntry
End Sub
 
J

Jay Freedman

Greg said:
Thanks Gents,

I did reply last night, but see this morning that it didn't transmit.
I have had a few error messages the past two days using OE that
newsgroups coudn't be resolved?

Anyway, thanks for both replies. Jezebel, by working I just meant the
code would run without generating a runtime error. With your reply
and Jay's I see now why it would and the others wouldn't. It was a
poor example.

The basic problem was this. I wanted an error handler that when an
error was generated that it would simply ignore it an go on to save
the document. I was working with TestA below which worked OK except
when the user canceled or "X" out of the SaveAs Dialog. It would
then throw and error while in the error handler.

Sub TestA()
On Error GoTo Err_Handler
MsgBox ActiveDocument.Bookmarks(1).Range.Text
'Other Stuff
Exit Sub
Err_Handler:
ActiveDocument.Save
End Sub

I can work throug that issue using this construction. Do either of
you see problems with this method? Thanks.

Sub TestB()
On Error GoTo Err_Handler
MsgBox ActiveDocument.Bookmarks(1).Range.Text
'Other Stuff
Exit Sub
Err_ReEntry:
On Error Resume Next
ActiveDocument.Save
Exit Sub
Err_Handler:
Resume Err_ReEntry
End Sub

Your TestB will work, and that style is common. But I personally find it
nonlinear and unintuitive, sending execution down to the bottom of the code
only to make it jump back to the point of the error. Besides that, if there
are multiple places in the routine that could trigger several different
kinds of errors, they all wind up going through Err_Handler and back to
wherever the error was. It can be a nightmare to debug, especially with
data-dependent errors.

I prefer a more linear and localized style, like this:

Sub TestJ()
On Error Resume Next
MsgBox ActiveDocument.Bookmarks(1).Range.Text
If Err.Number > 0 Then ' or just If Err.Number Then
Err.Clear
ActiveDocument.Save
Exit Sub
End If
'Other Stuff
End Sub

Each statement that could trigger an error can have a separate "error
handler" within an If Err.Number .. End If clause that immediately follows
that statement. You can nest these If clauses, one within another. If one
statement could trigger several kinds of errors, you can replace the simple
If clause with an If Err.Number = X .. ElseIf Err.Number = Y .. End If or a
Select Case Err.Number statement to do different things for different
errors. [If you program in other languages, you may recognize this style as
VBA's dumbed-down version of Try .. Catch blocks.]

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the newsgroup so
all may benefit.
 
G

Greg Maxey

Thanks Jay,


Jay said:
Greg said:
Thanks Gents,

I did reply last night, but see this morning that it didn't transmit.
I have had a few error messages the past two days using OE that
newsgroups coudn't be resolved?

Anyway, thanks for both replies. Jezebel, by working I just meant the
code would run without generating a runtime error. With your reply
and Jay's I see now why it would and the others wouldn't. It was a
poor example.

The basic problem was this. I wanted an error handler that when an
error was generated that it would simply ignore it an go on to save
the document. I was working with TestA below which worked OK except
when the user canceled or "X" out of the SaveAs Dialog. It would
then throw and error while in the error handler.

Sub TestA()
On Error GoTo Err_Handler
MsgBox ActiveDocument.Bookmarks(1).Range.Text
'Other Stuff
Exit Sub
Err_Handler:
ActiveDocument.Save
End Sub

I can work throug that issue using this construction. Do either of
you see problems with this method? Thanks.

Sub TestB()
On Error GoTo Err_Handler
MsgBox ActiveDocument.Bookmarks(1).Range.Text
'Other Stuff
Exit Sub
Err_ReEntry:
On Error Resume Next
ActiveDocument.Save
Exit Sub
Err_Handler:
Resume Err_ReEntry
End Sub

Your TestB will work, and that style is common. But I personally find it
nonlinear and unintuitive, sending execution down to the bottom of the code
only to make it jump back to the point of the error. Besides that, if there
are multiple places in the routine that could trigger several different
kinds of errors, they all wind up going through Err_Handler and back to
wherever the error was. It can be a nightmare to debug, especially with
data-dependent errors.

I prefer a more linear and localized style, like this:

Sub TestJ()
On Error Resume Next
MsgBox ActiveDocument.Bookmarks(1).Range.Text
If Err.Number > 0 Then ' or just If Err.Number Then
Err.Clear
ActiveDocument.Save
Exit Sub
End If
'Other Stuff
End Sub

Each statement that could trigger an error can have a separate "error
handler" within an If Err.Number .. End If clause that immediately follows
that statement. You can nest these If clauses, one within another. If one
statement could trigger several kinds of errors, you can replace the simple
If clause with an If Err.Number = X .. ElseIf Err.Number = Y .. End If or a
Select Case Err.Number statement to do different things for different
errors. [If you program in other languages, you may recognize this style as
VBA's dumbed-down version of Try .. Catch blocks.]

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the newsgroup so
all may benefit.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top