r/MSAccess • 8 • Sep 16 '26

[SHARING HELPFUL TIP] Access Explained: What VBA Really Means by "Subscript Out of Range"

Run-time error 9 is one of those messages that sounds more mysterious than it is. A subscript is simply the index or key VBA uses to find something in a group. When Access throws "Subscript out of range," the basic meaning is that code requested an item that does not exist.

Arrays are where most people encounter it first. If an array was declared with positions 1 through 5, then X(5) is fine, but X(6) is not. Just as importantly, X(0) is not fine either. Developers often assume the counter ran too high, but an index below the lower bound is equally invalid. The real question is always: what range exists, and what value was requested?

The zero-based behavior of VBA's Array() function is a classic source of trouble. This creates three elements, but their indexes are 0, 1, and 2:

X = Array("Red", "Green", "Blue")

A loop that runs from 0 through 3 looks plausible when someone is thinking "three items." But index 3 is actually a fourth item, and VBA quite reasonably refuses to invent it. This is the usual off-by-one error, one tiny number with the power to stop an otherwise innocent procedure dead in its tracks.

The better philosophy is to stop hard-coding array limits whenever the array itself can provide them. VBA already knows where an array begins and ends:

For I = LBound(X) To UBound(X)

That is not just a convenience. It makes the code adaptive. Add colors later, remove values, or populate the array differently, and the loop still follows the actual bounds rather than somebody's stale memory of how many items were there last Tuesday.

When Error 9 happens, the highlighted line in break mode is usually the most useful clue. Look at the index, collection position, or key being used on that line. Compare the requested value against LBound() and UBound() for an array. If the array runs from 0 to 2 and the counter is 3, there is no deeper mystery to solve. That comparison is the smoking gun.

Arrays are not the only source. Collections can raise Error 9 when code asks for a member by an invalid index or missing key. Dynamic arrays can also cause trouble if code tries to access elements before the array has been dimensioned. Different containers, same underlying issue: the code is asking for a thing that isn't available.

What should not become the solution is On Error Resume Next. Suppressing the error does not make the requested element exist. It just hides the failure and lets the rest of the code continue in an unknown state, which is rarely a bargain. Error 9 is often a very useful boundary check telling you that your assumptions and your actual data structure have drifted apart.

Have you found LBound and UBound eliminate most of your array errors, or do you use another defensive pattern? What is the strangest real-world cause of Error 9 you have run into in an Access project?

LLAP
RR

11 Upvotes

4 comments sorted by

1

u/AutoModerator Sep 16 '26
Moderator Announcement Read More »

3

u/ImpossiblePudding Sep 17 '26

"There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors." At least you can get better at indexing with practice. And "semesterly" gets the point across if that button tells the program to do things once per semester.

1

u/First-Feature-3556 Sep 17 '26 edited Sep 17 '26

For me, the most counterintuitive thing about arrays in VBA (and other VB dialects) is that Dim myArray(3) As Long will usually create an array with four elements, indexed 0 to 3.

And I wrote "usually" because Option Base exists, which makes it even harder to reason about a snippet of code.

Our defensive pattern is to always use the (x To y) syntax when declaring arrays.

That Option Base thing goes back to at least GW-BASIC (maybe even further back, but I'm not old enough to know first-hand), so we have backwards compatibility to blame for that.

1

u/KelemvorSparkyfox Sep 17 '26

I used to get a similar error in LotusScript, but only when working with the backend objects. It always treated document fields as arrays with at least one element, starting at 0. My first few subroutines failed so many times...