Change_scene_to_packed not working after it's worked so far

Godot Version

4.3

Question

So I’ve been using change_scene_to_packed for my transitions, with an @export to the packed scene loaded in from the inspector, and keeping reference to my important objects in a GameManager in an autoload/singleton. All of that works through 3 scene changes

Thusly so when goings from title screen into the main scene:

extends Button
# Very complex script...
@export var main_scene : PackedScene


func _on_pressed():
    get_tree().change_scene_to_packed(main_scene)

Or even when going into a temporary scene:

extends TargetArea


var player_is_in : bool = false
var temp_base_scene : PackedScene = preload("res://scenes/temp_base_scene.tscn")

@onready var label: Label = $Label


func _ready() -> void:
    label.modulate.a = 0.0


func _on_body_entered(body: Node2D) -> void:
    if body.is_in_group("player_ship"):
        player_is_in = true
        var tween = create_tween()
        tween.tween_property(label,"modulate:a", 1.0, 1.0)

        label.text = "Press P to disable your ship and land"


func _on_body_exited(body: Node2D) -> void:
    if body.is_in_group("player_ship"):
        player_is_in = false
        var tween = create_tween()
        tween.tween_property(label,"modulate:a", 0.0, 1.0)



func _input(event: InputEvent) -> void:
    if event.is_action_pressed("disable ship"):
        if player_is_in:
            label.text = "Welcome aboard, Captain!"
            await get_tree().create_timer(3.0).timeout
            get_tree().change_scene_to_packed(temp_base_scene)

Then a simple button to go to another from button scene it works:

extends Node2D

@export var ship_editor : PackedScene

func _on_button_pressed() -> void:
    get_tree().change_scene_to_packed(ship_editor)

These work fine. But in this instance I cannot use the same pattern. I have to open it by file or I get an error:

extends Node2D

# GUI Controls for Ship parts
@export var part_button : Control
@export var part_list : Control
@export var selected_text : Control
@export var cam : Camera2D

@export var node_overlay : PackedScene

@export var store_part_button : Control
@export var store_part_list : Control
@export var store_parts : Array[PackedScene]
# why the Keebler's E.L. Fudge does a packed scene work in every other instance?
# @export var main_scene : PackedScene # doesn't work
@export_file var main_scene

# GUI Controls for Store parts
# ...

var ship
var parts = []


# Some other code here

# do with button poosh>
func _on_to_main_pressed() -> void:
    print(main_scene)
    get_tree().change_scene_to_file(main_scene)
    #get_tree().change_scene_to_packed(main_scene) # no worky

I’m getting this error from the scene the last script is in:

E 0:00:01:0718   _parse_ext_resource: res://scenes/shop/ship_editor.tscn:32 - Parse Error: [ext_resource] referenced non-existent resource at: res://scenes/Main.tscn
  <C++ Source>   scene/resources/resource_format_text.cpp:159 @ _parse_ext_resource()

And this error from when I try to use change_scene_to_packed in that fourth script instead of file:

E 0:00:33:0374   ShipEditor.gd:66 @ _on_to_main_pressed(): Can't change to a null scene. Use unload_current_scene() if you wish to unload it.
  <C++ Error>    Condition "p_scene.is_null()" is true. Returning: ERR_INVALID_PARAMETER
  <C++ Source>   scene/main/scene_tree.cpp:1430 @ change_scene_to_packed()
  <Stack Trace>  ShipEditor.gd:66 @ _on_to_main_pressed()

So I understand that for some reason the main_scene isn’t in the @export-ed value’s variable set in the inspector, nor does setting it with a non @export var and preload() as I did in the second script.

So it’s null in the fourth case, I know why it’s not working but why did it work before? My deduction is it has something to do with the fact that it was loaded before, but I’m not sure why that happens yet. I then suspect someone will tell me and I will feel silly because I should have or knew, buried in my brain, under the piles of thoughts and game ideas.

I guess I could switch to using change_scene_to_file, but I lose the ability to move my scenes in the editor to new locations when doing house keeping and refactoring.

Posibly cyclic preloading, check if main scene have preload/export valiable with packed scene type to ship_editor scene.

But first error said about non-existent resource, may be if you select this scene in FileSystem Tab, press RMB and select Edit Dependencies... you will see problem

I think it is a cyclic reference. The problem is maybe that it’s not clear from the error and it’s in this issue here I think Switching back to previously loaded scene fails using load_scene_from_packed · Issue #93258 · godotengine/godot · GitHub

Thanks for the help. It just seems weird that it works that way and I’ve gotten this far. I have another project where I’m going between scenes and I’ll look to see what I’m forgetting there.

@export variable with packed scene is same as preload
Older versions of Godot (4.1 for ex.) allowed cyclic preload in editor, but after export you got a problem and sometimes when you close and reopen one of scenes you can got message - scene is corrupt

Yeah, my other project, I probably had the same issue and just used load with constant resource paths, but this doesn’t help if you move the scenes around… I guess it’s a small problem.

I am not sure why but change_scene_to_packed never truly worked for me because once you change your scene from a packed scene to something else, godot instantly loses hold to the prior packed scene because it threw the packedScene away.

I always make do with instantiating the scene and adding it to the sceneTree as a child while removing the former scene.

I’m guessing it’s because the @export var scene type usage uses preload() for the resource. Then that variable becomes something like a static reference, any further @exports you make will point to the same resource in memory, regardless of where it is. When change_scene_to_packed is called, it queue_free()'s that single reference. Preload() has to work that way because it loads things at the start of the engine runtime and doesn’t allow multiple instances of a resource in the preloaded space. Not sure why that is considered cyclic if the reference is getting destroyed, not there to be referenced in the first place. I think the problem is that things in preloaded space shouldn’t be permanently dead references but I’d have to know how that worked in the engine better. I might be missing something and just making bad assumptions.