Quick answer: Godot 4 replaced yield with await. An await only resumes if the signal is emitted after it starts waiting, by an object that still exists. Signals emitted earlier are missed, a freed emitter never emits, and calling a coroutine without await lets the caller run on immediately.

The function prints its first line, hits await, and is never heard from again. Coroutines in GDScript are simple, but they assume the signal is still coming. These are the ways it never does.

Godot 3 code: yield

yield(get_tree().create_timer(1.0), "timeout") is a parse error in Godot 4. The equivalents:

await get_tree().create_timer(1.0).timeout
await $AnimationPlayer.animation_finished
var result = await some_coroutine()

Cause 1: the signal already fired

await does not remember past emissions. In this code the animation can finish before the await is reached if anything in between takes a frame:

$Anim.play("open")
await load_level_async()        # takes longer than the animation
await $Anim.animation_finished  # already emitted -- waits forever

Start waiting before triggering, or check state instead of waiting:

if $Anim.is_playing():
    await $Anim.animation_finished

Cause 2: the emitter was freed

If the node whose signal you await is freed before emitting — an enemy killed by something else while you await its died — nothing ever resumes the coroutine. Emit before queue_free(), or await something that outlives the node.

Cause 3: the signal is never emitted on this path

animation_finished is not emitted for looping animations. body_entered is not emitted for bodies already inside the area. A Timer that is stopped never times out. Check the class docs for when the signal fires, and confirm with a temporary connection that prints.

Cause 4: the caller does not wait

Any function containing await is a coroutine. Calling it without await runs it until its first await, then returns to the caller immediately:

func _ready():
    play_intro()          # returns at the first await inside
    start_game()          # runs while the intro is still playing

func _ready():
    await play_intro()    # waits for the whole intro
    start_game()

Cause 5: pause and time scale

A SceneTreeTimer keeps running while paused by default (process_always is true), but a Timer node with a pausable process mode stops, and Engine.time_scale = 0 freezes both. An await on such a timer during a pause menu waits until the game is unpaused.

Cause 6: the object running the coroutine was freed

If the node whose function is waiting is freed, the function cannot resume; Godot reports an error about the instance being gone when the signal arrives. Long-running sequences (cutscenes, tutorials) belong on nodes that live for the whole sequence, such as an autoload.

Debugging tip

Print before and after each await with the frame number (Engine.get_process_frames()). The last line printed shows which signal you are stuck on.

Related fixes