QuickStart: Error Propagation

What is Error Propagation?

Let's say we have two procedures - namely Foo and Bar. Foo has local error handling yet Bar does not. Foo calls Bar and Bar generates an exception. Since there is no error handling in Bar, the error 'propagates' back to Foo where it is handled there. This is how error handling works in both VBA and VB6.

Public Sub Foo()

On Error Goto ErrorRoutine

    Call Bar
    Exit Sub

ErrorRoutine:
    MsgBox "An error has occurred in Foo"

End Sub

Public Sub Bar()

    Debug.Print 1 / 0    ' This will force an exception, but will be handled in Foo

End Sub

How we handle error propagation in our Global Error Handler

In your global error handling procedure you can detect when an error will be propagated back to an earlier procedure in the call stack by examining the ErrEx.State value.  In this case, ErrEx.State will equal the constant value OnErrorPropagate.

If when your global error handler exits, the ErrEx.State still equals OnErrorPropagate (i.e. you haven't changed the value) then the code flow will continue at the last procedure in the call stack that has error handling enabled (i.e. 'Foo' in this example).

In other words you don't need to do anything special in order to support error propagation as it complies with how VBA (and VB6) works normally - just be aware of it and how to use it.

Logging details of propagating errors

When a propagating error occurs, you might find it useful to log the source of the error ('Bar' in the example) and also the routine that will ultimately handle the error ('Foo' in the example).

We already have details of 'Bar' as this is at the top of the call stack, so ErrEx.SourceProcedure will give us that.

To find details of the procedure that will ultimately handle the error, we need to find the first match in the call stack that has active error handling - and it's that simple. (Remember that the call stack is backwards - where 'Bar' is the first item, 'Foo' the second etc).

To do this, we use ErrEx.CallStack.HasActiveErrorHandler:

Public Sub MyGlobalErrorHandler()

    Select Case ErrEx.State

        Case OnErrorGoto0
        '...       

        Case OnErrorGotoLabel
        '...

        Case OnErrorPropagate
        
            With ErrEx.CallStack
            
                .FirstLevel
            
                Do
        
                    If .HasActiveErrorHandler = True Then
                
                        strErrorWillPropagateTo = .ProjectName & "." & .ModuleName & "." & .ProcedureName
                        Exit Do
                
                    End If
                
                Loop While .NextLevel
    
            End With

    '...

    End Select

End Sub