Skip to content

is_in_tree returns false even though node is in tree #107921

@Watersilver

Description

@Watersilver

Tested versions

  • Reproducible in: v4.4.1.stable.official [49a5bc7], v4.2.stable.official [46dc277]

System information

Godot v4.4.1.stable - Windows 10 (build 19045) - Multi-window, 2 monitors - OpenGL 3 (Compatibility) - NVIDIA GeForce RTX 2060 (NVIDIA; 32.0.15.6094) - 11th Gen Intel(R) Core(TM) i7-11700K @ 3.60GHz (16 threads)

Issue description

I have a level manager that packs its children (rooms) as scenes so they can be instantiated when appropriate. Here's a simplified version of how it does that:

## This node packs all its children as scenes

extends Node2D
class_name Packer

var packed: Array[PackedScene] = []

func _ready() -> void:
	# Iterate children to pack them as scenes
	for child in get_children():
		
		# set the owner of every descendant of child to child so it will get packed too
		for subchild in child.find_children("*"):
			subchild.owner = child
		
		# For some reason packing works even when commenting out the following line
		remove_child(child) # But in my actual project it doesn't
		
		# Store in packed scenes array
		var p := PackedScene.new()
		p.pack(child)
		packed.push_back(p)
		
		
		child.queue_free()

Under certain conditions some children nodes of the scene that was packed by the level manager exist inside the scene tree (I checked the remote scene tree) even though their is_in_tree method returns false. I also can't interact with them properly. For example if I change their position, nothing happens visually. At that point if I remove_child on the buggy node and then re-add it, it seems to get duplicated even though the remote scene tree only shows one instance of it. This can be seen when the buggy node is a sprite because there are two of them on screen and one of them in the remote scene tree.

The conditions seem to be:

  • The buggy node must be part of a different scene, not the level manager or packer or whatever scene packs it
  • It must not be the root node of that different scene
  • The different scene itself must not be a child of the node that does the packing, it must be the child of the child (or presumably any descendant)
  • The buggy node must have a unique name and be accessed in its scene by its unique name. I found this out after a lot of testing

So the node hierarchy for the packer should be something like:
Packer
|Child
||Subchild(scene that bugs out)

And the node hierarchy for the buggy scene should be something like:
Root
|%UniqueNamedChild


I've discovered a "fix" for the packing code that avoids the issue. When setting ownership for the subchildren (yeah I know it's a weird name, couldn't think of anything better) I avoid changing owner for the ones that are children that belong to a different scene. They still get packed for some reason, even though the docs say that the sub-nodes (ah that's where I got the subchildren idea...) are only packed when owned. I assume that's because the child scene is itself packed recursively and it owns its children.

It's also possible to avoid the issue if you don't use unique names.

However the issue with the duplication and the node that appears on screen but not the scene tree has gotten me a bit anxious about memory leaks and I'm not sure if either of these workarounds are safe. If anyone takes a look at the source code please let me know if they are safe ways to circumvent the issue.

Steps to reproduce

The MRP has only three scenes.

A Packer scene that contains the code I linked above along with the "fix" I described (can be toggled on and off in the editor).
A SubchildScene (ugh) that simply prints if its Sprite2D child is_inside_tree and also has a in editor toggle to remove and re-add causing the duplication if it's bugged.
A main scene that runs when you run the project. It has two buttons to load the two scenes the packer has packed. The fist one isn't bugged in any way that I've seen, as they're nodes belonging to the packer scene, but the second is bugged.

If you use the toggles you can see everything I described above except the non unique name workaround so if you go to the SubchildScene and replace the % with a $ you can see that too.

Minimal reproduction project (MRP)

not-inside-tree.zip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions