Communication between Autoload and UI fails

Godot Version

4.2.2 - stable

Question

Hello,
So I just tried to implement a system for saving and loading my game progress. I felt it necessary to have all the variables to be saved in one place. To this end, I’m trying to build a GameController.

Scripts that worked perfectly fine in my Mainscene are now not working anymore. And I just can’t see where the error is.
Here’s the setup:

Previously:
→ Mainscene saves the current level, player position, and the number of collectible fruits.
→ Mainscene sends a message to UI when a fruit is collected.
→ UI updates the displayed text showing how many fruits have been collected (Label).

Now:
→ Game Controller (an AutoLoad Script of type NODE) is supposed to handle the collectables (to eventually save them as well).
→ Game Controller is supposed to send the number of fruits to the UI.
→ Game crashed with the error: “Attempting to call function ‘collectFruits’ in base ‘null instance’ on a ‘null instance’.”

Here is the corresponding code from the Game Controller:

var currentFruits : int
var fruitsAmount : int = 0
@onready var uiLayer = $UI
@onready var fruits = get_tree().get_nodes_in_group("fruits")
func _ready():
	print (fruits)
	for each in fruits:
		each.addOneFruit.connect(_on_fruit_collected)
		print (each)
	uiLayer.collectFruits(fruitsAmount)
	

func _on_fruit_collected():
	fruitsAmount += 1
	uiLayer.collectFruits(fruitsAmount)

And this is the script inside the uiLayer:

extends CanvasLayer
	
func collectFruits(amount):
	$Collectables.text = "Früchte: " + str(amount)

any Ideas why the Autoload Script cant see the UI, but the same script, placed in the mainscene can?
Thank you for helping.

try change to this:

var currentFruits : int
var fruitsAmount : int = 0
var uiLayer
@onready var fruits = get_tree().get_nodes_in_group("fruits")
func _ready():
	print (fruits)
	for each in fruits:
		each.addOneFruit.connect(_on_fruit_collected)
		print (each)
	uiLayer =get_node("/root/UI")
	uiLayer.collectFruits(fruitsAmount)
	

func _on_fruit_collected():
	fruitsAmount += 1
	uiLayer.collectFruits(fruitsAmount)

Hey, thank you for the answer.

but that doesn´t work. uiLayer still remains

<Object#null>

I already tried to load the Controllerscript in the ready function of the mainscene. But then I lost all my access to the tree. Like in

get_tree().get_nodes_in_group(“fruits”)

It seems like I’m forced to keep everything in my Mainscene. This is already causing me headaches because I still want to create an intro and a start menu, which would also take place before the Mainscene (which is currently my first level).

I probably should have known all of this beforehand and should have approached the whole project differently from the beginning.

i assume your fruits here also [] value?

because on theory, the autoload is first load when the game boot, then anything inside the root node loaded and added into whole root node is what you actually see. it could happen that the node you try to get in root node is not yet add_child, hence why it would be null

i would say it’s a bad practice to use autoload to reference a node in the Root node, but the documentation for autoload actually tell how to do that by using something like this: =get_node("/root/UI") what you can still try with the code i send is to add
await get_tree().physics_frame before you try to get node the UI node

so in before this:

or change it completely to:

	uiLayer =get_tree().get_root().get_child(0).get_node("UI")

this get_node("/root/UI") doesnt work because your main scene is not named “UI”
the UI is inside the main scene which i dont know what you named as, so this path will return null