Help! Godot 4.x Editor Thinks async and // are Syntax Errors

Godot Version

Godot_v4.4.1-stable_win64

Question

Hi everyone,

I’m working on a Tetris project and have run into a very strange problem that I can’t solve. My Godot editor is reporting parse errors on basic GDScript 2.0 keywords, and I’m hoping someone has seen this before.

The Problem:

My script editor flags valid Godot 4 syntax as errors. For example:

Using the integer division operator // gives the error: Parse Error: Expected expression after “/” operator.

Using the async keyword gives the error: Unexpected identifier “async” in class body.

This is the behavior of a Godot 3 editor, but I am certain I am running the latest version.

My Environment:

Godot Version: I have downloaded the latest stable version of Godot 4. The editor’s title bar confirms it is a v4.x.x version.

Version Type: I am using the standard version, not the .NET/C# version.

Operating System: Windows 10

What I Have Already Tried:

I’ve spent a long time trying to debug this. I have already:

Confirmed the version number in the editor’s title bar.

Downloaded a completely fresh copy of the latest Godot 4 engine.

Deleted and manually recreated the script files to check for hidden/invisible characters.

Deleted the .godot cache folder inside my project and let the editor re-import everything.

Created a brand new, empty project. The error still happens even in a clean project. A script with only var x = 10 // 2 immediately shows a parse error.

My Question:

Has anyone ever encountered this? Why would a confirmed Godot 4 editor completely fail to parse its own basic syntax? I am starting to think it might be an issue with my PC’s configuration, but I don’t know where to look.

Any ideas or suggestions would be greatly appreciated. Thank you!

async is not a GDScript keyword in Godot 4.x

There isn’t an integer division operator (//) in GDScript

Here’s the GDScript reference.

4 Likes

Just rewrite

var x = 10 // 2

as

var x = 10 / 2

In Godot 4 you can also implicitly declare x as type int:

var x: int = 10 / 2

Async and yield were removed and replaced by await. If you want to do an asynchronous call, you can either emit a signal…

signal kickoff

func foo() -> void:
	kickoff.emit()

Or you can use await…

func foo() -> bool:
	await get_tree().create_timer(0.5).timeout

func play_volume_confirm_sound(bus_name: String = ui_bus_name) -> void:
	var audio_stream_player: AudioStreamPlayer = AudioStreamPlayer.new()
	add_child(audio_stream_player)
	audio_stream_player.bus = bus_name
	audio_stream_player.stream = volume_confirm_sound
	audio_stream_player.play()
	await audio_stream_player.finished #Here's our await, which waits for the AudioStreamPlayer to finish playing, then continues.
	audio_stream_player.queue_free()
1 Like

Thank you very much for help

1 Like

Godot signals are not asynchronous.

You’re right @sancho2 they are not.

@Vidhura_Wimaladasa if you want a signal to be truly asynchronous, whatever is listening for the signal will need to use multithreading.

If you’re coming from JavaScript and used something like React, you may be used to an asynchronous structure, because it’s really helpful in web development. Game development is different because ultimately you’re inside a finite state machine under the hood. Godot actually hides the implementation of the FSM, but it’s a giant loop that happens 60 times a second (by default). So it might be worth reconsidering if what you want to do needs to be truly asynchronous.

Here’s some additional learning on multithreading.

I also forgot to mention using a timer on its own - that actually appears asynchronous, in that the code continues running, checking in with the timer every frame.

var timer

func _ready() -> void:
	timer = $Timer #Assumes you setup a timer node, it can be one-shot or continuous
	timer.start()
	timer.timeout.connect(_on_timeout)

func _on_timeout() -> void:
	# Do something
1 Like