VBAtoPython
Start Conversion

VBA ReDim 0 to -1 Error

Why VBA dynamic arrays end up with bounds 0 to -1, what causes the Subscript out of range crash, and the Python list pattern that avoids the whole problem.

What “0 to -1” actually means

When VBA reports an array as having bounds 0 to -1, it's telling you the array is allocated but contains zero elements. The lower bound is 0, the upper bound is -1, and any subscript access (even index 0) throws Subscript out of range.

Key insight: a dynamic array declared with Dim arr() As Type but neverReDim'd also reports as 0 to -1 in some VBA hosts — the diagnostic looks identical to a deliberately zero-sized array.

The two common causes

1. ReDim'ing a dynamic array to size 0

VBA — crashes

Dim items() As String
ReDim items(0 To n - 1)  ' n = 0 here

' UBound = -1, LBound = 0
For i = LBound(items) To UBound(items)
    Debug.Print items(i)  ' never runs
Next i

items(0) = "x"  ' Subscript out of range

VBA — fix

Dim items() As String
If n > 0 Then
    ReDim items(0 To n - 1)
    For i = 0 To n - 1
        items(i) = "..."
    Next i
End If
' Don't touch items at all when n = 0

2. Declared-but-never-ReDim'd dynamic array

VBA — crashes

Dim results() As Double
' (no ReDim — never sized)

' UBound throws "Subscript out of range"
' or returns -1 depending on host
Debug.Print UBound(results)
results(0) = 1.0  ' crash

VBA — fix

Dim results() As Double

' Guard with the (Not arr) Is Nothing trick:
If (Not results) = -1 Then
    ReDim results(0 To 9)
End If

results(0) = 1.0  ' safe

The (Not arr) = -1 idiom is VBA's undocumented check for an uninitialized dynamic array — see the related guide on the ReDim Preserve uninitialized array error.

The Python pattern that avoids it entirely

Python lists don't carry separate lower and upper bound integers — an empty list is just [], and iterating it does nothing. There is no “0 to -1” condition to guard against.

VBA (defensive)

Dim items() As String
ReDim items(0 To n - 1)

If n > 0 Then
    For i = 0 To n - 1
        Debug.Print items(i)
    Next i
End If

Python (no guard needed)

items = [None] * n  # n = 0 → items = []

for x in items:
    print(x)  # loops zero times when empty
            # no Subscript out of range
            # no LBound / UBound check

Iterating a Python list is safe regardless of length. len([]) == 0, and for x in []: simply skips the loop body. The 0-to-(-1) class of bug doesn't exist.

How the converter handles it

VBAtoPython rewrites ReDim arr(0 To n - 1) as arr = [None] * n directly, and converts the entire If n > 0 Then ... End If guard into the empty-iteration-safe Python loop. The 0-to-(-1) defensive code disappears because Python doesn't need it.

Edge case: if your VBA uses UBound(arr) after a conditional ReDim, the converter flags it for review — the Python idiom depends on whether you want len(arr) - 1 or just direct iteration.

Related

Convert your VBA arrays

The free converter rewrites ReDim patterns into idiomatic Python — and skips the 0-to-(-1) defensive code automatically.