When a VBA macro encounters a runtime error, Excel’s default error message displays the error number and description, but it does not reveal the line number where the failure occurred. When code runs on another user’s machine—where the VBA editor cannot be opened in break mode—tracking down the failing line can require guessing. The hidden VBA function Erl solves this problem by returning the exact line number of the statement that triggered the error.
Quick Answer
Add numerical line labels (such as
10:,20:,30:) at the start of key statements in your procedures. In your error handling block, query the built-inErlfunction alongsideErr.NumberandErr.Description. If an error occurs,Erlreturns the line label number of the failing statement.
What Is the Erl Function?
Erl (Error Line) is an undocumented, built-in function native to the VBA runtime engine. It requires no external library references or setup.
- If an error occurs on a statement that has a line number label,
Erlreturns that line number as aLong. - If the failing statement has no line label,
Erlreturns0. - If a procedure uses line labels intermittently,
Erlreturns the most recent line label passed prior to the crash.
Code Execution Flow:
10: Set wb = Workbooks.Open("data.xlsx") <-- Success
20: Set ws = wb.Sheets("Inventory") <-- Crash! Sheet does not exist
Error Handler Traps Error:
Err.Number = 9 (Subscript out of range)
Err.Description = "Subscript out of range"
Erl = 20 <-- Pinpoints exact failure point
Step-by-Step Implementation: Using Erl in Production Code
1. Basic Implementation with Explicit Line Labels
To use Erl, place numeric labels at the beginning of executable lines, followed by a colon or space:
Public Sub ProcessMonthlyReport()
On Error GoTo ErrorTrap
10: Dim wb As Workbook
20: Dim ws As Worksheet
30: Dim lastRow As Long
40: Set wb = Workbooks.Open("C:\Reports\MonthlyData.xlsx")
50: Set ws = wb.Sheets("SummaryData")
60: lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
70: ws.Range("B2:B" & lastRow).Value = ws.Range("A2:A" & lastRow).Value * 1.15
80: wb.Close SaveChanges:=True
Exit Sub
ErrorTrap:
Dim errorMsg As String
errorMsg = "Macro execution failed!" & vbCrLf & _
"Error Code: " & Err.Number & vbCrLf & _
"Description: " & Err.Description & vbCrLf & _
"Failing Line: " & Erl
MsgBox errorMsg, vbCritical, "Runtime Diagnostic Failure"
' Clean up open resources if needed
If Not wb Is Nothing Then wb.Close SaveChanges:=False
End Sub
If "MonthlyData.xlsx" is missing, the message box reports Failing Line: 40. If the sheet "SummaryData" is missing or renamed, it reports Failing Line: 50.
Diagnostic Best Practices: Label Numbering Strategies
You do not need to label every single line of code. Labeling every statement adds visual clutter and makes routines harder to read. Use these strategic approaches instead:
Strategy A: Milestone Block Numbering (Recommended)
Place line labels only at the start of operational blocks or statements that interact with outside resources (such as opening files, querying databases, or working with dynamic ranges):
Sub ImportData()
On Error GoTo ErrHandler
100: ' --- Initialization ---
Dim conn As Object
Set conn = CreateObject("ADODB.Connection")
200: ' --- Database Connection ---
conn.Open "Provider=MSOLEDBSQL;Data Source=Server01;..."
300: ' --- Data Extraction ---
Dim rs As Object
Set rs = conn.Execute("SELECT * FROM Inventory")
400: ' --- Worksheet Output ---
Sheet1.Range("A2").CopyFromRecordset rs
Exit Sub
ErrHandler:
MsgBox "Failure in execution block: " & Erl & " - " & Err.Description
End Sub
If conn.Open fails due to network dropouts, Erl returns 200, pointing straight to the connection block.
Strategy B: Automated Line Numbering via Add-Ins
For large enterprise codebases containing thousands of lines, adding line labels by hand is impractical. Most professional VBA developers use free developer add-ins (such as MZ-Tools) to automatically inject and remove line numbers across entire projects before distributing files to end users.
If you add and remove code lines frequently during maintenance, export and re-import your modules to clear any residual compiled code using Cleaning up the “VBA Project Junk” using code export/import.
Diagnosing Why Erl Returns 0
If your error handling block triggers but Erl reports 0, work through this checklist:
- Missing Line Labels: There are no numeric labels before the statement that failed. If a crash occurs between line
50and an unlabelled line,Erlreports50. But if the error happens before the first label in the procedure,Erlreturns0. - Error Raised in a Called Subroutine: If Procedure A calls Procedure B, and Procedure B crashes without its own error handler, execution bubbles up to Procedure A’s handler. In this case,
Erlreturns the line number from Procedure A where the call occurred—not the line inside Procedure B. - Labels Used Non-Numeric Text: Text labels (like
ErrorHandler:,Step1:, orCleanup:) are valid jump targets forGoTo, but they are ignored byErl. Only whole numbers (e.g.,10:,20:) register with theErlparser.
Combining Erl with Real-Time Debugging Tools
During development, you can inspect Erl directly in the Immediate Window while troubleshooting paused code:
? Erl
60
Review the techniques in How to use the Immediate Window to debug variable values in real-time to test failing lines interactively.
When debugging issues that only appear intermittently in production, combine Erl with silent logging rather than modal dialogs. Use Debug.Print: The developer’s best friend for silent error logging or write the line number, timestamp, and user ID to an external text file.
For procedures that need temporary code pauses rather than permanent line labels during initial testing, compare your options in The “Stop” statement vs. “Breakpoints”: When to use each.