Introduction to Error Handling

Submitted on: 1/7/2015 6:49:00 AM
By: James Vincent Carnicelli (from psc cd)  
Level: Beginner
User Rating: By 6 Users
Compatibility: VB 3.0, VB 4.0 (16-bit), VB 4.0 (32-bit), VB 5.0, VB 6.0, VB Script, ASP (Active Server Pages)
Views: 2829
     This article introduces you to the basic concepts behind Visual Basic's run-time error handling methodology. You'll learn what causes run-time errors, how to deal with them, and how to generate them yourself. A good understanding of run-time errors is critical to becoming a seasoned VB programmer. Arm yourself now.

				All VB programmers feel the kiss of death when they see a familiar run-time error message box that looks a little like this:

Microsoft Visual Basic

Run-time error '381':

Invalid property array index


If you've compiled a program to an executable (.EXE) and this sort of error pops up, you know by now that you don't get to debug the program. It just crashes. Is that what you want to happen? Probably not. But then, you probably wouldn't want a program to start acting unpredictably or worse because of an unexpected state of corruption. That's what critical run-time errors are supposed to prevent.

But what if you actually do expect certain kinds of errors and want your program to continue running despite them? You can "trap" and handle these errors. To "trap" an error simply means to allow an error to occur on the assumption that your code will deal with it. There are two basic ways to trap and handle an error: "resume" and "go-to". They can be illustrated by the following examples:

    '"Resume" approach
    Sub Demo1
        On Error Resume Next
        X = 1 / 0 'Division by zero
        MsgBox Err.Description
        On Error GoTo 0
    End Sub
    '"Go-To" approach
    'This is not currently applicable to VBScript
    Sub Demo2
        On Error GoTo Oopsie
        X = 1 / 0 'Division by zero
        Exit Sub Oopsie:     MsgBox Err.Description End Sub

The key difference between these two approaches to error handling is that On Error Resume Next tells VB you want your code to keep executing as if nothing had happened, whereas On Error GoTo Some_Label tells VB you want execution to jump to some specific location in your routine at any time a run-time error occurs.

Notice the use of On Error GoTo 0 in Demo1 above? Although it looks like a contorted version of On Error GoTo Label, it's actually a special way to tell VB that you want to stop trapping errors and let VB perform its own built-in handling.

Recovering gracefully from a run-time error, once you've trapped it, really requires you to make use of the Err object. Err is an object VB uses to give your program access to information about the error. Here are the most important public members Err exposes:

Err.Number Long integer indicating the error code number. This is pretty much useless except where the vendor of the product that generated this error was too lazy to provide a useful description.
Err.Source Generally used to tell your handler what component or code element is responsible for generating the error. With custom errors, you might want to set this to "ModuleName.MethodName()".
Err.Description The all-important, human-readable description. The point of this is so you're not left scratching your head wondering "what the heck does '-10021627' mean?"
Err.Clear() Allows you to sweep the error under the rug, so to speak.
Err.Raise(Number, [Source], [Description], [HelpFile], [HelpContext]) Allows you to "raise", or invoke, your own run-time error. Number can be vbObjectError + CustomErrorCode if you're not raising one of the standard ones. Be sure to provide a source and description.

The .HelpFile and .HelpContext properties, not listed above, can be used by your program to refer users to a relevant passage in some help file. Few programs bother.

The nice thing about go-to error trapping is that it allows you to easily enwrap a large chunk of code with your error handler with one single line of code (On Error GoTo Label). The resume approach really requires you to either include error handling code after every line or to take a blind leap of faith that a given line will either never encounter an error or that it won't matter. As a general rule, use On Error Resume Next only for short blocks of code.

One of the interesting nuances of the VB run-time error mechanism is that it propagates errors "backwards". To illustrate what this means, consider the following code:

    Sub A
        On Error Resume Next
        Call B
        MsgBox Err.Description
    End Sub
    Sub B
        Call C
    End Sub
    Sub C
        X = 1 / 0 'Division by zero
    End Sub

A calls B, which in turn calls C. Since C will cause a division-by-zero run-time error and itself has no error handler, VB will effectively leave C and go back to B. But B doesn't have an error handler, either, so VB leaves B to go back to A. Fortunately, A does have an error handler. If it didn't, A would also immediately exit and control would go back to whatever called it. If there's nothing left up this "calling stack", your program will courteously commit suicide.

You can use this "backward propagation" property of VB's error mechanism to your advantage in many ways. First, you can enwrap a block of code by putting it in its own subroutine and putting your error handler in the code that calls that subroutine. In this case, any run-time error in that subroutine will propagate back to your calling code. Second, you can add value to an error message by adding more context information. You might use code like the following, for instance:

    Sub A
        On Error GoTo AwShoot
        Call B
        Exit Sub
        Err.Raise vbObjectError, "MyModule.A(): " & Err.Source, _
          "Unexpected failure in A: " & Err.Description
    End Sub
    Sub B
        On Error GoTo AwShoot
        Err.Raise vbObjectError, "My left nostril", "Stabbing pain"
        Exit Sub
        Err.Raise vbObjectError, "MyModule.B(): " & Err.Source, _
          "Couldn't complete B: " & Err.Description
    End Sub

Calling A will result in an error whose source is "MyModule.A(): MyModule.B(): My left nostril" and whose description is "Unexpected failure in A: Couldn't complete B: Stabbing pain". Having the extra "source" information probably won't help your end-users. But then, your end users probably won't care about the source of the problem, any way. But as the person who gets to fix it, this will be invaluable to you. The extra description information might actually help your end users, but it too will be invaluable to you. Note, incidentally, that calling Err.Raise() in your error handler will not cause the error to be thrown back to itself, again. With the go-to method of error handling, as soon as the error is raised and before control is passed to your error handler (right after the AwShoot: line label), the error handler for your routine is automatically switched off. If you want to trap errors in your error handler code, you'll have to reset the error handler with another On Error Resume Next or On Error GoTo Some_Other_Label line in your handler.

For those times you use the resume approach, be aware that calling On Error GoTo 0 not only disables error handling in the current routine, it also clears the current error properties, including the description. If you want to add your own custom error message before propagating the error back up the call stack in a fashion like that above, you'll need to grab the properties from Err, first. Here's a simple way to do it:

    Sub Doodad
        On Error Resume Next
        X = 1 / 0
        If Err.Number <> 0 Then         'Dump Err properties into an array         EP = Array(Err.Number, Err.Source, _           Err.Description, Err.HelpFile, Err.HelpContext)         'Re-enable VB's own error handler         On Error GoTo 0         'Propagate error back up the call stack with my two cents added         Err.Raise EP(0), "MyModule.Doodad(): ", EP(1), _           "Something bad happened: " & EP(2), EP(3), EP(4)     End If     On Error GoTo 0
        Exit Sub End Sub

Finally, let me strongly urge you to have your programs raise errors as a natural matter of course. Functions often return special values like 0, "", Null and so on to indicate that an error has occurred. Instead of doing this and requiring your users (other programmers) to figure out your special error representations and to make non-standard error handlers for them, try calling Err.Raise(). If your users don't realize that an invocation of your code may cause an error, the first case may leave them with a difficult mystery to solve, whereas the second case will leave little doubt about the real cause. Plus, they'll be able to make their code more readable and consistent with best-practice standards.

In summary, VB's run-time error trapping and handling mechanism allows your code to take control of how errors are managed. This can be used to allow your programs to more gracefully end, to let your programs continue running despite certain kinds of problems, to give developers better clues about the causes of bugs in their code, and more. There are two basic approaches: "resume" and "go-to". VB's built-in Err object holds the information you need to find out where the error occurred and what its nature is and allows you to clear or raise errors of your own.

Other 20 submission(s) by this author


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Beginner category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)

Other User Comments

 There are no comments on this submission.

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)

To post feedback, first please login.