Scene instantiated but not added to the scene tree casues the parent node properties to be lost

Godot Version

Godot v4.7.1 stable

Question

My first time using the forum! completely new to Godot and C# in general so sorry if the question being too native. Here I found a weird behavior occur to node referencing on scene that’s being instantiated outside of the scene tree. Where let’s say I have a main scene call MainScene and a EndScene I want to transit to. For EndScene its a Control node with a Label child node named TextHolder. The Control node has the following script

public partial class EndScene : Control
{
	private Label _TextHolder;
	public Label TextHolder
	{
		get => _TextHolder;
		set => _TextHolder = value;
	}
	public override void _Ready()
	{
		TextHolder = GetNode<Label>("TextHolder");
		TextHolder.Text = "Hello";
	}
}

And the EndScene scene is store at res://end.tscn. Now in the main scene script:

public partial class MainScene : Node2D
{
	private PackedScene End = GD.Load<PackedScene>("res://end.tscn");
	public override void _Ready()
	{
		EndScene endscene = End.Instantiate() as EndScene;
		endscene.TextHolder.Text = "Hi";
		GetTree().ChangeSceneToNode(endscene);
	}
}

Would result in the program getting stuck at the statment endscene.TextHolder.Text = "Hi"; due to endscene.TextHolder being null. If I remove this problematic line and run, the EndScene can display the text “Hello” which seems to indicate that EndScene.TextHolder works fine in EndScene script.

so I thought maybe all the child node instances after the _ready() function in EndScene would be discarded as I did not put the endscene to the scene tree which causes the reference type property TextHolder to be null. Yet if I use endscene.GetChilden() from the main script like such:

public partial class MainScene : Node2D
{
	private PackedScene End = GD.Load<PackedScene>("res://end.tscn");
	public override void _Ready()
	{
		EndScene endscene = End.Instantiate() as EndScene;
		GD.print(endscene.GetChilden());
	}
}

It will show that endscene indeed has a Label child node attach to it. So My question is, why does such a strange behavior happen which I can’t get the reference of the child node despite it is still there?

It’s not “strange behavior”. It behaves as expected. _Ready() runs after the scene is added to the scene tree. Since you initialize TextHolder in _Ready() in will be null until that.

Ah now I see, thank you very much! I was wrong because I thought Instantiate() would call the _Ready() function for some reason, at least now I know.