content

Ran into an interesting bug while working on no signal offline.

I noticed that when creating a new game and skipping the PGEIST intro, Godot throws this error: Trying to assign to invalid previously freed instance.

The code in question looks something like this:

static func reset_lighting(tree: SceneTree) -> void:
	var lights := Lookup.children_where(
		tree.root, func(a: Node) -> bool: return a is Light3D
	)

	# elided

	# Wait for rendering data to be reset
	await RenderingServer.frame_post_draw

	# Re-enable rendering stuff
	for light: Light3D in lights:
		if is_instance_valid(light):
			light.visible = true

This doesn't make sense, because I explicitly check if the light is valid before I try to access the visible property.

Looking up this issue, I find this:

[...] When you specify a type for the iteration variable, it seems there is some reassigning/casting happening under the hood (I’m not completely sure and haven’t checked the source yet).

You can remove the type in the for to fix it. [...]

In particular, it's important to note that Lookup.children_where returns an untyped array, even though every element in that array is a Light3D. Since I set debug/gdscript/warnings/unsafe_property_access to true, it's necessary to specify the type later to resolve the compilation warning. Changing the affected section to delay setting the type fixes the issue:

	for light in lights:
		if is_instance_valid(light):
			var l: Light3D = light
			l.visible = true

meta

created:

backlinks: no signal

commit: 8005ffc4