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 rangeVBA — 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 = 02. 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 ' safeThe (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 IfPython (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 checkIterating 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
- ReDim Preserve Uninitialized Array Error — The sibling error and how to guard against it.
- VBA Arrays & ReDim to Python Lists — The full umbrella guide for arrays.
- VBA Error Handling to Python — On Error patterns mapped to try/except.
Convert your VBA arrays
The free converter rewrites ReDim patterns into idiomatic Python — and skips the 0-to-(-1) defensive code automatically.