Find more errors in Godot, with a script

15. May 2025

I learned programming with Java, a statically typed language. For that reason, I really miss errors at compile time, when programming with GDScript in Godot. GDScript is a dynamically typed language, that makes error detection at compile time nearly impossible.

There are many ways to make GDScript more strict, like adding type hints and making it statically typed. Additionally, treating more warnings as errors in its warning system, will also have a positive effect on the amount of errors you will get.

Anyways, some errors will only pop up, when you execute the script file that has the error. Just change the name of a variable or a method and forget to update all references. BOOM, your game will crash when the previous name get's accessed. And in the worst case, this happens to the final user.

Yet another script to the rescue

There is one trick that triggers the error: opening the script in the editor. But it's impossible to open all files every time you make a change, by hand. Given this, a good way to get more errors is to open all script files, inside a script ;-)
So I created a script to search and load all .gd and .tscn files in the project. This will then trigger some errors, you probably would have missed. By opening also scene files, you might also catch dependency errors, after renaming files for example.

extends Node


func _ready() -> void:
	print("load all scenes...")
	var scene_paths: Array[String] = find_files(".tscn")
	# load scripts and check for possible dependency errors while loading
	for path: String in scene_paths:
		var TestScene: PackedScene = load(path)
		assert(TestScene != null)
		var instance: Node = TestScene.instantiate()
		assert(instance != null)
	print("load all scene done.")

	print("load all scripts...")
	var script_paths: Array[String] = find_files(".gd")
	# load scripts and check for possible runtime errors while loading
	for path: String in script_paths:
		var TestScript: GDScript = load(path)
		assert(TestScript != null)
	print("load all scripts done.")


func find_files(suffix: String, path: String = "res://") -> Array[String]:
	var scripts: Array[String] = []
	var dir: DirAccess = DirAccess.open(path)
	if dir == null:
		print("error while opening %s" % path)
		return scripts

	dir.list_dir_begin()
	var file_name: String = dir.get_next()
	while not file_name.is_empty():
		var full_path: String = path + file_name
		if dir.current_is_dir():
			scripts.append_array(find_files(suffix, full_path + "/"))
		elif file_name.ends_with(suffix):
			scripts.append(full_path)
		file_name = dir.get_next()

	return scripts

This script can be executed by being attached to a scene that gets launched from the editor. It can also be invoked from a bigger test suite, like I wrote for my game 99Managers Futsal Edition.

There I test also game logic and make sure that I don't make mistakes twice. It also gives much more confidence, that the code is running as expected, after yet another refactoring session. I have to admit, I love refactoring, so having tests helps a lot to keep the code working as expected.

What's next

I already extended the script in my game to do even more, like linting and checking for dumb mistakes. But that would be too much for this blog post. If you still want to check it out, you can find the script on Codeberg and Github.

Another idea I have is to run it as main scene of the game, so it will run every time I launch the game. If the test passes, the splash screen gets loaded. Except when the game is not running from the editor, in that case the splash screen will be loaded immediately.

Every feedback is welcome

Feel free to write me an email at info@simondalvai.org and comment on Mastodon.

mastodon button Codeberg button Email button RSS button