@OnReady Returning Null

Godot Version

Godot v4.3

Question

` Recently updated from Godot v3 to v4.3, and sorting through the changes this has done to my code. However, one particular issue I cannot seem to solve:
When declaring “@onready” vars for child nodes, it’s saying those nodes are null.

Perhaps a bit more specifically the function is being called on “Visibility Changed” signals going off. This doesn’t happen when running the scene individually, only when loading the game at large.

I can’t quite figure out why Visibilty Changed functions are firing off before onready vars are run, and this wasn’t a problem in v3 so I’m stumped. Anybody got suggestions?`

So in case of race conditions I have temporarily added “await self.ready” to every “VisibilityChanged” signal that was causing it and it’s working but this is by no means an effective long-term solution.

Is your settings menu a global?

It’s a scene that’s a child of another menu, which is a child of the root node for the entire game, if that’s what you’re wondering, that is it’s running from the start of runtime.

If it’s not what you’re thinking of I might need a bit of guidance in this case on what Global is going to refer to in Godot; are you thinking Auto-run scripts? Because if so, no.

Worth mentioning; this isn’t the only case. Anything that has had “Visibility_changed” signals being used, this is happening to.

Globals/Autoload/SIngleton it has too many names in Godot, a common issue is adding the script as an Autoload rather than the scene, this makes no children which is what your error looks like, but it’s irrelevant, your SettingsMenu is not a Global/Autoload/Singleton

Could you show more of your script? Like the line that produces the error? Make sure to paste scripts instead of screenshots

Sure; as below:

extends Control

signal menu_closed

@onready var main_settings_menu = $MainSettingsMenu
@onready var audio_settings = $AudioSettingsMenu
@onready var unlock_manager = get_node("/root/World/UnlocksManager")

@onready var master_slider = $AudioSettingsMenu/CenterContainer/VBoxContainer/MasterSliderBox/MasterSlider
@onready var music_slider = $AudioSettingsMenu/CenterContainer/VBoxContainer/MusicSliderBox/MusicSlider
@onready var sound_effect_slider = $AudioSettingsMenu/CenterContainer/VBoxContainer/SFXSliderBox/SFXSlider
@onready var ambience_slider = $AudioSettingsMenu/CenterContainer/VBoxContainer/AmbienceSliderBox/AmbienceSlider
var last_master_value = 0
var reset_sliders = false

func _on_Back_pressed():
	emit_signal("menu_closed")


func _on_AudioSettings_pressed():
	setupSliders()
	audio_settings.show()
	main_settings_menu.hide()

func _on_AudioBack_pressed():
	main_settings_menu.show()
	audio_settings.hide()


func _on_SettingsMenu_visibility_changed():
	await self.ready
	if visible == false:
	       main_settings_menu.show()
		audio_settings.hide()


#audio controls
#==============================================================================
func setupSliders(): #Used when sliders appear to set them to the right values
	reset_sliders = true
	master_slider.value = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Master"))
	music_slider.value = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Music"))
	sound_effect_slider.value = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("SFX"))
	ambience_slider.value = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Ambience"))

#Line up all audio to master
func compareSlidersToMaster():
	if music_slider.value > master_slider.value:
		music_slider.value = master_slider.value
	if sound_effect_slider.value > master_slider.value:
		sound_effect_slider.value = master_slider.value
	if ambience_slider.value > master_slider.value:
		ambience_slider.value = master_slider.value

func scaleSliderValues(new_value):
	if !reset_sliders:
		var scalar = new_value - last_master_value #Make the increase value
		music_slider.value += scalar
		sound_effect_slider.value += scalar
		ambience_slider.value += scalar
	else:
		reset_sliders = false
	last_master_value = new_value

func _on_MasterSlider_value_changed(value):
	#scaleSliderValues(value) #Scale the rest of the sliders up or down
	#compareSlidersToMaster()
	AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), value)

func _on_MusicSlider_value_changed(value):
	#compareSlidersToMaster()
	AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Music"), value)

func _on_SFXSlider_value_changed(value):
	#compareSlidersToMaster()
	AudioServer.set_bus_volume_db(AudioServer.get_bus_index("SFX"), value)

func _on_AmbienceSlider_value_changed(value):
	#compareSlidersToMaster()
	AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Ambience"), value)


func _on_ResetUnlocks_pressed():
	unlock_manager.resetUnlocks()

This is the specific one in question, the specific function in particular is _on_SettingsMenu_visibility_changed(), however this extended to all of my functions relying on Visibility-based signal (on_visibility_changed, on_screen_enter, as quick examples), which are running before ready.

I did add “await self.ready” for them as a temporary measure after first posting, but as said it’s not permanent if possible