resume: Resumed function ” after yield, but class instance is gone

Using yield in GoDot (3.2.2 or <) isn’t quite as fun as they are selling it. If you are using a yield for some game-logic, you probably did encounter this exception message.

resume: Resumed function '' after yield, but class instance is gone.
Method failed. Returning: Variant()
     modules/gdscript/gdscript_function.cpp:1882 @ resume() @ yield_wait()

Let us re-construct the issue real quick:

 yield(get_tree().create_timer(1.0), "timeout")

set_visible (just a random function call) will throw an exception, if between the yield and the set_visible the object has been removed (queue_free). That issue has been reported back in 2017 and 2018, but is still present up to this day. The community does offer several inconvenient solutions to this problem. But all of them suck, so here is mine: Add a new global script (e.g.: and add it to the auto load. Copy and paste this code:

func yield_wait(var timeout : float, var parent = get_tree().get_root()):

    var timeoutCap = max(0, timeout) 

    if timeoutCap <= 0:     

    var timer =

    yield(yield_call_deferred(parent, "add_child", timer), "completed")     
    yield(_yield_wait(timer), "completed")
    yield(yield_call_deferred(parent, "remove_child", timer), "completed") #avoid orphans

func _yield_wait(var timer : Timer):
    yield(timer, "timeout")

func yield_call_deferred(var node, var action, var parameter):
    node.call_deferred(action, parameter)
    yield(get_tree(), "idle_frame")

Back to our original example, we require to change our code to following:

 yield(Functions.yield_wait(1.0, self), "completed")

The trick is simple: We add a new timer node to the caller as a child. Thus, if the parent has been queue_freed, then the timer will be gone as well. In case you wonder why yield(timer, “timeout”) isn’t inlined:

"Condition 'p_elem->_root!=this' is true." errors when adding nodes from a thread
0 0 votes
Article Rating
Notify of
Inline Feedbacks
View all comments