This is due to the fact that ipairs is a baselib function that utilizes the iterator triplet construct (which in turn allows us to store only one state variable, while we would need two state variables here). If ipairs was a language construct that just behaves like "for i = 1, #t do local v = t[i]; ... end", then we wouldn't have a problem here.
But that one state variable can contain a table, so you can store as much state as you want.