VBAtoPython
Start Conversion

VBA Error Handling to Python

VBA uses On Error statements and the Err object to handle runtime errors. Python replaces this entirely with structured try/except blocks, giving you clearer control flow and more readable error handling.

On Error Resume Next

On Error Resume Next tells VBA to silently ignore errors and continue execution on the next line. In Python, wrap the risky operation in a try/except block with pass to achieve the same effect.

VBA

Sub SafeDivide()
    On Error Resume Next
    Dim result As Double
    result = 10 / 0    ' No crash
    result = 10 / 2    ' Continues here
    MsgBox result
End Sub

Python

def safe_divide():
    try:
        result = 10 / 0
    except ZeroDivisionError:
        pass  # Silently ignore

    result = 10 / 2  # Continues here
    print(result)

Unlike VBA, Python encourages you to catch specific exceptions rather than silencing all errors globally.

On Error GoTo Label

VBA's On Error GoTo jumps to a labeled section when an error occurs. Python's try/except block is the direct equivalent, with the except clause acting as the error handler.

VBA

Sub OpenFile()
    On Error GoTo ErrorHandler

    Open "C:\data.txt" For Input As #1
    ' ... process file ...
    Close #1
    Exit Sub

ErrorHandler:
    MsgBox "Error " & Err.Number & _
           ": " & Err.Description
End Sub

Python

def open_file():
    try:
        with open("data.txt") as f:
            # ... process file ...
            pass
    except FileNotFoundError as e:
        print(f"Error: {e}")
    except PermissionError as e:
        print(f"Error: {e}")

On Error GoTo 0

On Error GoTo 0 resets the error handler, so subsequent errors crash normally. In Python, this concept is unnecessary because try/except blocks are scoped: code outside the block is not protected.

VBA

Sub PartialProtection()
    On Error Resume Next
    ' Protected section
    val = CLng("abc")   ' Error ignored

    On Error GoTo 0
    ' Unprotected section
    val = CLng("xyz")   ' This WILL crash
End Sub

Python

def partial_protection():
    # Protected section
    try:
        val = int("abc")  # Error caught
    except ValueError:
        pass

    # Unprotected section
    val = int("xyz")  # This WILL crash

Python's block scoping makes it obvious which lines are protected and which are not, unlike VBA's global On Error state.

Err.Number and Err.Description

VBA's Err object exposes Number and Description properties. In Python, the caught exception object carries all relevant information, and you can access the exception type and message directly.

VBA

Sub CheckError()
    On Error Resume Next
    Dim x As Double
    x = 1 / 0

    If Err.Number <> 0 Then
        Debug.Print "Error #" & Err.Number
        Debug.Print Err.Description
        Debug.Print Err.Source
        Err.Clear
    End If
End Sub

Python

def check_error():
    try:
        x = 1 / 0
    except Exception as e:
        print(f"Type: {type(e).__name__}")
        print(f"Message: {e}")
        # e.args contains all arguments
        # No need to "clear" - scoped
VBA Err ObjectPython Exception
Err.Numbertype(e).__name__
Err.Descriptionstr(e)
Err.ClearNot needed (scoped)
Err.Raise n, src, descraise ValueError(desc)

Resume and Resume Next

VBA's Resume retries the failed line, while Resume Next skips to the line after the failure. Python handles these patterns differently using loops and control flow.

VBA (Resume - retry)

Sub RetryExample()
    On Error GoTo RetryHandler
    Dim filePath As String
    filePath = InputBox("Enter path:")
    Open filePath For Input As #1
    Exit Sub

RetryHandler:
    filePath = "C:\default.txt"
    Resume  ' Retry with new path
End Sub

Python (retry with loop)

def retry_example():
    file_path = input("Enter path: ")
    while True:
        try:
            f = open(file_path)
            break  # Success, exit loop
        except FileNotFoundError:
            file_path = "default.txt"
            # Loop retries with new path

Nested Error Handlers

VBA supports nested error handlers but they can be confusing because only one On Error handler is active at a time per procedure. Python's nested try/except blocks are explicit and easier to follow.

VBA

Sub NestedHandlers()
    On Error GoTo OuterHandler

    ' Outer protected code
    Dim ws As Worksheet
    Set ws = Sheets("Data")

    On Error GoTo InnerHandler
    ' Inner protected code
    ws.Range("A1").Value = 1 / 0
    Exit Sub

InnerHandler:
    Debug.Print "Cell error ignored"
    Resume Next

OuterHandler:
    Debug.Print "Sheet not found"
End Sub

Python

def nested_handlers():
    try:
        # Outer protected code
        ws = workbook["Data"]

        try:
            # Inner protected code
            ws["A1"] = 1 / 0
        except ZeroDivisionError:
            print("Cell error ignored")

    except KeyError:
        print("Sheet not found")

Cleanup Code (Finally)

VBA has no Finally equivalent. Developers typically duplicate cleanup code in both the normal path and the error handler. Python's try/except/finally solves this cleanly.

VBA

Sub WithCleanup()
    On Error GoTo ErrHandler

    Application.ScreenUpdating = False
    ' ... do work ...

CleanUp:
    Application.ScreenUpdating = True
    Exit Sub

ErrHandler:
    MsgBox Err.Description
    GoTo CleanUp
End Sub

Python

def with_cleanup():
    try:
        app.screen_updating = False
        # ... do work ...
    except Exception as e:
        print(str(e))
    finally:
        # Always runs, error or not
        app.screen_updating = True

Best Practices for Migrating Error Handling

  • Avoid blanket exception catching. Replace On Error Resume Next with targeted try/except blocks that catch specific exception types like ValueError, KeyError, or FileNotFoundError.
  • Narrow the scope. VBA's On Error applies to an entire procedure. In Python, wrap only the lines that might fail in the try block, keeping the rest outside.
  • Use finally for cleanup. Any code that must run regardless of errors (closing files, resetting state) belongs in a finally block or a with statement.
  • Replace Err.Raise with custom exceptions. Instead of raising error numbers, define meaningful exception classes: class InvalidInputError(ValueError): pass.
  • Use logging instead of Debug.Print. Python's logging module supports levels (debug, info, warning, error) and can write to files, consoles, or external services.
  • Leverage context managers. Python's with statement automatically handles resource cleanup. Use with open(path) as f: instead of manual Open/Close patterns.

Have VBA code with error handling?

Paste your VBA macro into the converter and get clean Python with proper try/except blocks instantly.