Godot v4.3.stable - Windows 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1660 SUPER (NVIDIA; 32.0.15.6590) - Intel(R) Core(TM) i7-10700F CPU @ 2.90GHz (16 Threads)
Issue description
When you make an anonymous lambda that contains a reference to a local variable or function in the current script where the lambda is defined, and then this lambda is later called when the current node is missing, Godot can (unpredictably) bind this lambda to a completely different node.
In the case that the new node does not have the same members, it will throw an error like in the screenshot below, which is super confusing. But an even more dangerous case I have encountered is if the new node does share the same members being referenced in the lambda (i.e. position or name). In this case, the lambda will silently proceed with the wrong target node as though nothing is wrong, leading to a silent bug that can be almost impossible to diagnose.
In the screenshot below, the story.gd script attached to the story node is where the error occurs. The lambda being constructed contains a call to a function _perform_place_transition which is local to story.gd. However, at runtime, the lambda construction fails. The error message and the self field in the debugger window both say that the error is occuring on a completely different node in the scene - the tf_mirror node under the right eye of a penguin.
Godot will randomly re-bind the lambda to one of a few other nodes, or it will not re-bind at all. There appears to be no pattern as to how it chooses how/whether to re-bind.
The problem line of code:
Game.loader.queue_load_op(func(): await _perform_place_transition(place_name, spawn_point_name))
The rebinding bug still occurs if the lambda does not contain an await:
Game.loader.queue_load_op(func(): _perform_place_transition(place_name, spawn_point_name))
The rebinding bug does NOT occur if an anonymous lambda is not used:
Game.loader.queue_load_op(_perform_place_transition.bind(place_name, spawn_point_name))
Just to be clear:
It is a user bug to allow an anonymous lambda to be invoked on a no-longer-valid object. The bug being reported here is the random re-binding being done by Godot.
Steps to reproduce
I can't share my entire commercial project, and I have attempted but not succeeded in making a reduced or fresh repro project.
Tested versions
Reproducible in 4.3.stable
System information
Godot v4.3.stable - Windows 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1660 SUPER (NVIDIA; 32.0.15.6590) - Intel(R) Core(TM) i7-10700F CPU @ 2.90GHz (16 Threads)
Issue description
When you make an anonymous lambda that contains a reference to a local variable or function in the current script where the lambda is defined, and then this lambda is later called when the current node is missing, Godot can (unpredictably) bind this lambda to a completely different node.
In the case that the new node does not have the same members, it will throw an error like in the screenshot below, which is super confusing. But an even more dangerous case I have encountered is if the new node does share the same members being referenced in the lambda (i.e.
position
orname
). In this case, the lambda will silently proceed with the wrong target node as though nothing is wrong, leading to a silent bug that can be almost impossible to diagnose.In the screenshot below, the
story.gd
script attached to thestory
node is where the error occurs. The lambda being constructed contains a call to a function_perform_place_transition
which is local tostory.gd
. However, at runtime, the lambda construction fails. The error message and theself
field in the debugger window both say that the error is occuring on a completely different node in the scene - thetf_mirror
node under the right eye of a penguin.Godot will randomly re-bind the lambda to one of a few other nodes, or it will not re-bind at all. There appears to be no pattern as to how it chooses how/whether to re-bind.
The problem line of code:
Game.loader.queue_load_op(func(): await _perform_place_transition(place_name, spawn_point_name))
The rebinding bug still occurs if the lambda does not contain anawait
:Game.loader.queue_load_op(func(): _perform_place_transition(place_name, spawn_point_name))
The rebinding bug does NOT occur if an anonymous lambda is not used:Game.loader.queue_load_op(_perform_place_transition.bind(place_name, spawn_point_name))
Just to be clear: It is a user bug to allow an anonymous lambda to be invoked on a no-longer-valid object. The bug being reported here is the random re-binding being done by Godot.
Steps to reproduce
I can't share my entire commercial project, and I have attempted but not succeeded in making a reduced or fresh repro project.
Minimal reproduction project (MRP)
N/A