Quick answer: _ready runs bottom-up — children before parents. If a child’s _ready depends on the parent being initialized, use call_deferred or await get_tree().process_frame so the cross-node setup happens after the whole subtree is ready.
You instantiate a PackedScene, the parent’s _ready sets up a bunch of data, and a child script crashes with Invalid get index trying to access that data. The error is misleading — the data is there, the child just ran first. Godot’s lifecycle order is well-defined once you know it, but it trips up every new Godot developer at least once.
The Order
When a scene loads, Godot walks the tree in a specific order. For a scene with a parent and two children:
_initruns on every node at construction (order: depends on instantiation)._enter_treeruns top-down: parent first, then children._readyruns bottom-up: children first, then parent._processand_physics_processbegin on the next frame.
The key thing to internalize: inside a parent’s _ready, every child has already finished its own _ready. Inside a child’s _ready, the parent is in a tree but has not yet finished initializing.
Why This Makes Sense
The bottom-up order is correct for most cases. Parents usually aggregate child information — a Menu parent that needs to know how many Buttons it has, or a Map that wants to list its Tiles. If the parent ran first, it would have to re-scan children later. With bottom-up, children initialize themselves, and by the time the parent runs, every child is done.
The bug only appears when a child depends on the parent — which is actually the unusual direction. The fix is to defer that cross-parent access.
The Common Bug
# Parent script
extends Node
var config: Dictionary = {}
func _ready():
config = {"enemy_count": 5, "difficulty": "hard"}
# Child script
extends Node
func _ready():
var cfg = get_parent().config # parent.config is still {} here!
print(cfg.enemy_count) # Key not found error
The child runs first. get_parent().config is still the empty dictionary. By the time the parent’s _ready assigns values to config, the child has already moved on.
The Fix
Option 1: Move parent setup to _init.
If the parent’s data can be initialized without knowing about children, put it in _init or at declaration time. _init runs before any _ready, so the data is guaranteed to be available.
extends Node
var config: Dictionary = {"enemy_count": 5, "difficulty": "hard"}
Option 2: Defer the child’s cross-node access.
extends Node
func _ready():
call_deferred("_setup_from_parent")
func _setup_from_parent():
var cfg = get_parent().config
print(cfg.enemy_count)
call_deferred queues the call to run after the current frame of processing finishes. By then, every _ready in the tree has run, so the parent’s state is stable.
Option 3: Use await.
extends Node
func _ready():
await get_tree().process_frame
var cfg = get_parent().config
print(cfg.enemy_count)
The await pauses the coroutine until the next frame. Same effect as call_deferred but with cleaner syntax for longer setup sequences.
Option 4: Let the parent push, not the child pull.
Invert the dependency. Instead of the child asking the parent for data, the parent initializes its children with the data in its own _ready:
extends Node
var config = {"enemy_count": 5}
func _ready():
for child in get_children():
if child.has_method("init_from_config"):
child.init_from_config(config)
This is the cleanest pattern for most cases. Children do not need to know how to find their parent, and the parent controls the init order explicitly.
The @onready Shortcut
Godot 4 has an @onready annotation that defers variable initialization to _ready time. It is useful for references to child nodes but does not change the order — a child’s @onready still runs before the parent’s @onready.
Verifying the Fix
Add print statements with node names to each _ready. Run the scene. You will see children print first, then parents, from deepest to shallowest. If your logic expects the opposite order, reorganize the code or add call_deferred.
“In Godot, trust the children. Children are always ready before their parents — which means the parent can safely use them, but the children cannot safely use the parent until the next frame.”
Related Issues
For signal-related ready timing issues, see Godot signal firing before child nodes ready. For get_node returning null, see Godot get_node returns null in ready. For object lifetime bugs at teardown, see Godot object freed while signal pending.
When in doubt, parent pushes data to children, never the other way around. It sidesteps every _ready ordering bug.