Trying to call an async function without "await" in Godot 4

By Eduardo Orellana · Updated

The called function contains await, so it is a coroutine, and its return value was used without await in front of the call. Put await before the call, var count = await loader.load_level(), so the line waits for the function to finish and gets its real return value.

What Godot is checking

A function that contains await is a coroutine. When it reaches its first await it returns to the caller straight away, and what it returns at that point is a GDScriptFunctionState object, not the value from its return statement.

When a call's return value is used, the VM looks at what came back. If it is a GDScriptFunctionState and the call was not compiled as an awaited call, it stops with Trying to call an async function without "await". The check is inside DEBUG_ENABLED, so it runs in the editor and debug builds.

It is a runtime error: the script parsed, and the error appeared when the line ran. The function that made the call stops there, so the print("after") below it never ran, as the output shows.

The analyzer has its own check. When it knows which function is called and that it is a coroutine, a call used as a value stops the script at parse time with Function "load_level()" is a coroutine, so it must be called with "await". A call on its own line gets the MISSING_AWAIT warning instead. In the repro the call goes through an untyped variable, var loader = get_node("."), so the analyzer does not know the function, and the run shows it parsed and failed only when it ran.

Reproduce it

A load_level() function that waits one frame and returns a number, called through an untyped variable with its return value stored and no await.

extends Node

func load_level() -> int:
	await get_tree().process_frame
	return 3

func _ready() -> void:
	var loader = get_node(".")
	var count = loader.load_level()
	print("after ", count)

What Godot 4.7.2 prints

Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org

SCRIPT ERROR: Trying to call an async function without "await".
   at: _ready (res://answers/trying-to-call-an-async-function-without-await/repro.gd:9)
   GDScript backtrace (most recent call first):
       [0] _ready (res://answers/trying-to-call-an-async-function-without-await/repro.gd:9)

Fix it

Put await before the call. The line waits until load_level() returns, and count gets its return value.

extends Node

func load_level() -> int:
	await get_tree().process_frame
	return 3

func _ready() -> void:
	var loader = get_node(".")
	var count = await loader.load_level()
	print("level count ", count)

What the fixed script prints

Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org

level count 3

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 lines 1958 to 1966, the check and the message](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_vm.cpp#L1958-L1966), [gdscript_analyzer.cpp lines 3776 to 3784, the parse-time check and the MISSING_AWAIT warning](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_analyzer.cpp#L3776-L3784).

Questions

Why didn't the editor flag the call?
The analyzer checks for a missing await only when it knows the called function is a coroutine. Through an untyped variable it does not, so the call is checked when it runs, as in the repro.
Does the caller become a coroutine too?
Yes. A function that contains await is a coroutine, so once _ready() awaits load_level(), _ready() also returns to its own caller at that line and finishes later.