Unable to obtain iterator object of type 'Object' (but was obtained on first iteration?) in Godot 4
By Eduardo Orellana · Updated
The for loop got its first value from the object, but on a later pass the call to the object's _iter_get() failed, so the loop stopped. Keep the object able to answer _iter_init(), _iter_next() and _iter_get() until the loop ends: in the repro its script is swapped inside the loop, and the fix swaps it after the loop.
AppImage, x86_64. Ubuntu 22.04, Debian 12, Fedora 39 or newer.
Intel or AMD Chromebook, with Linux turned on.
What Godot is checking
A for loop over an untyped value runs two opcodes: ITERATE_BEGIN for the first pass and ITERATE for every pass after it. ITERATE_BEGIN calls the value's iter_init and ITERATE calls iter_next; both then call iter_get to read the loop variable.
For an object, iter_init and iter_next call the object's _iter_init() and _iter_next() with a one-element array, and iter_get calls _iter_get() with the counter. If that _iter_get() call does not return CALL_OK, for example because the object no longer has the method, iter_get reports the value as invalid.
When iter_get fails on the first pass, the VM prints Unable to obtain iterator object of type 'Object'. When iter_next succeeded but iter_get failed on a later pass, it prints this message, with (but was obtained on first iteration?) added. The type is the Variant type name of the value being looped over, so a custom iterator always reads 'Object'. The check is inside DEBUG_ENABLED, so it runs in the editor and debug builds.
The function stops at the for line. In the repro the loop printed stop dock, the body replaced the object's script with Ticker, which has _iter_init() and _iter_next() but no _iter_get(), and the next pass failed: print("after") never ran, as the output shows.
Reproduce it
A Route class iterates its stops with _iter_init(), _iter_next() and _iter_get(). The loop body swaps the object's script for Ticker, which has no _iter_get(), after the first stop.
extends Node
class Route:
var stops := ["dock", "mill", "farm"]
func _iter_init(arg: Array) -> bool:
arg[0] = 0
return arg[0] < stops.size()
func _iter_next(arg: Array) -> bool:
arg[0] += 1
return arg[0] < stops.size()
func _iter_get(iter: Variant) -> Variant:
return stops[iter]
class Ticker:
var stops := ["dock", "mill", "farm"]
func _iter_init(arg: Array) -> bool:
arg[0] = 0
return true
func _iter_next(arg: Array) -> bool:
arg[0] += 1
return arg[0] < stops.size()
func _ready() -> void:
var route = Route.new()
for stop in route:
print("stop ", stop)
if stop == "dock":
route.set_script(Ticker)
print("after")
What Godot 4.7.2 prints
Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org
stop dock
SCRIPT ERROR: Unable to obtain iterator object of type 'Object' (but was obtained on first iteration?).
at: _ready (res://answers/unable-to-obtain-iterator-object-but-was-obtained-on-first-iteration/repro.gd:33)
GDScript backtrace (most recent call first):
[0] _ready (res://answers/unable-to-obtain-iterator-object-but-was-obtained-on-first-iteration/repro.gd:33)Fix it
The loop only notes that a swap is wanted, and the script is replaced after the loop has ended, so every pass still reaches Route's _iter_get().
extends Node
class Route:
var stops := ["dock", "mill", "farm"]
func _iter_init(arg: Array) -> bool:
arg[0] = 0
return arg[0] < stops.size()
func _iter_next(arg: Array) -> bool:
arg[0] += 1
return arg[0] < stops.size()
func _iter_get(iter: Variant) -> Variant:
return stops[iter]
class Ticker:
var stops := ["dock", "mill", "farm"]
func _iter_init(arg: Array) -> bool:
arg[0] = 0
return true
func _iter_next(arg: Array) -> bool:
arg[0] += 1
return arg[0] < stops.size()
func _ready() -> void:
var route = Route.new()
var swap := false
for stop in route:
print("stop ", stop)
if stop == "dock":
swap = true
if swap:
route.set_script(Ticker)
print("script swapped after the loop")
What the fixed script prints
Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org
stop dock
stop mill
stop farm
script swapped after the loopThe object has no _iter_get() at all
If _iter_get() is missing from the start, the first pass fails and the VM prints the shorter message from ITERATE_BEGIN: Unable to obtain iterator object of type 'Object'. Add func _iter_get(iter: Variant) -> Variant that returns the value for the counter.
_iter_next() fails instead
If the object stops answering _iter_next(), or _iter_next() leaves the array it was given with a size other than one, iter_next reports the value as invalid first and the VM prints Unable to iterate on object of type 'Object' (type changed since first iteration?) instead.
Verified on Godot 4.7.2
Both scripts on this page were run headless on Godot 4.7.2 (4.7.2.stable.mono.official.ed1daf0bf) on 6 October 2026, and the output above is what Godot printed, unedited.
Where the check lives in Godot's source: [gdscript_vm.cpp lines 3446 to 3466, ITERATE and this message](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_vm.cpp#L3446-L3466), [gdscript_vm.cpp lines 3040 to 3059, ITERATE_BEGIN and the first-pass messages](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_vm.cpp#L3040-L3059), [variant_setget.cpp lines 1813 to 1818, iter_get calls _iter_get() and fails on a call error](https://github.com/godotengine/godot/blob/4.7.2-stable/core/variant/variant_setget.cpp#L1813-L1818), [variant_setget.cpp lines 1602 to 1630, iter_next calls _iter_next()](https://github.com/godotengine/godot/blob/4.7.2-stable/core/variant/variant_setget.cpp#L1602-L1630).
Questions
- Why does the message say 'Object' and not my class name?
- The VM builds it from Variant::get_type_name() of the looped value, which is the Variant type. Every object, whatever its class or script, is reported as 'Object'.
Related
- Invalid call to function '…' in base '…'. Expected N argument(s)
- Invalid access to property or key on a base object of type 'previously freed'
- Every verified Godot 4 answer
- Unable to iterate on object of type 'Nil' in Godot 4
- The variable type is being inferred from a Variant value, so it will be typed as Variant in Godot 4
- Trying to return a value of type "…" from a function whose return type is "…" in Godot 4
- Invalid access of index '…' on a base object of type: 'Array' in Godot 4
- Cannot get return value of call to "…()" because it returns "void" in Godot 4
Flockbay's agent reads Godot's debugger output and fixes errors like this one in your project, on the official Godot.
Download Flockbay free