Invalid access to property or key on a base object of type 'previously freed' in Godot 4
By Eduardo Orellana · Updated
The node your variable points at has been freed. Freeing a node, with free() or queue_free(), does not clear the variables that refer to it, so reading .position from one afterwards fails with this error. Check is_instance_valid() before using a reference that may outlive its node, and clear it when you free the node.
What Godot is checking
GDScript compiles enemy.position to a named property read. Before reading, the virtual machine checks that the object behind the reference still exists. When it was freed, there is no object to read from, the function stops, and Godot names the base 'previously freed'.
Freeing a node removes the object but does not reach the variables that refer to it. They keep the reference, and Godot names that case 'previously freed' instead of 'Nil'. On Godot 4.7.2 such a reference compares equal to null and is_instance_valid() returns false for it, as the fixed run below prints, but reading a property through it still stops the function.
queue_free() frees the node at the end of the current frame, so a reference read in the same frame still works and the error appears a frame later, often from a timer, a signal or _process.
Reproduce it
A script that makes a node, frees it, and then reads a property through the variable that still refers to it.
extends Node
var enemy: Node2D
func _ready() -> void:
enemy = Node2D.new()
add_child(enemy)
enemy.free()
print(enemy.position)
print("after")
What Godot 4.7.2 prints
Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org
SCRIPT ERROR: Invalid access to property or key 'position' on a base object of type 'previously freed'.
at: _ready (res://answers/invalid-access-to-property-or-key-on-previously-freed/repro.gd:9)
GDScript backtrace (most recent call first):
[0] _ready (res://answers/invalid-access-to-property-or-key-on-previously-freed/repro.gd:9)Fix it
Check the reference with is_instance_valid() before using it, and set the variable to null where you free the node, so later code sees an empty variable instead of a dead reference.
extends Node
var enemy: Node2D
func _ready() -> void:
enemy = Node2D.new()
add_child(enemy)
enemy.free()
print("is_instance_valid(enemy): ", is_instance_valid(enemy))
print("enemy == null: ", enemy == null)
if is_instance_valid(enemy):
print(enemy.position)
else:
print("enemy was freed, skipping it")
enemy = null
print("after")
What the fixed script prints
Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org
is_instance_valid(enemy): false
enemy == null: true
enemy was freed, skipping it
afterA signal or timer fires after the node is gone
A callback connected to something that outlives the node, such as a Timer elsewhere in the scene or an autoload's signal, can run after the node was freed and read it through a stored reference. Disconnect the signal when the node leaves the tree, or check is_instance_valid() at the top of the callback.
A list still holds freed nodes
An Array of enemies keeps its references after each enemy calls queue_free() on itself. Remove the node from the array when you free it, or filter the array with is_instance_valid before looping over it.
The same error in earlier Godot versions
Godot 4.0 to 4.2 printed it as: Invalid get index 'position' (on base: 'previously freed'). The cause and the fix are the same.
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 line 1281, the message](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_vm.cpp#L1281), [gdscript_vm.cpp lines 62 to 72, where 'previously freed' is named](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_vm.cpp#L62-L72).
Questions
- Why does the error say 'previously freed' and not 'Nil'?
- Freeing a node does not reach the variables that refer to it. They keep the reference to the freed object until you assign them again, and Godot names that case 'previously freed'.
- Does enemy == null catch a freed node?
- On Godot 4.7.2 it does: the fixed run on this page prints true for enemy == null after free(), and false for is_instance_valid(enemy). is_instance_valid() is the check that says what you mean, and it also covers a reference that was never assigned.
Related
- The same error on a base object of type 'Nil'
- The same error on a base object of type 'null instance'
- Invalid assignment of property or key on a base object of type 'Nil'
- Every verified Godot 4 answer
- Invalid call. Nonexistent function 'instance' in base 'PackedScene' in Godot 4
- Invalid call to function '…' in base '…'. Expected N argument(s) in Godot 4
- Trying to assign a non-object value to a variable of type '…' in Godot 4
- The "tool" keyword was removed in Godot 4: use @tool
- Invalid type in static function '…' in type '…'. Cannot convert argument 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