Quick answer: PackedScene.instantiate() returns null when the resource failed to load, typically due to an incorrect .tscn file path, a missing file, or calling the old Godot 3 method instance() instead of the Godot 4 method instantiate().

Here is how to fix Godot packed scene instantiation returning null. You call PackedScene.instantiate() and get null back. No crash, no error in the console—just a silent null that later causes a cascade of failures when you try to add the node to the scene tree. This is one of the most common and most frustrating issues in Godot 4, especially for developers migrating from Godot 3.

The Symptom

You have a scene file—say res://scenes/enemy.tscn—that you want to spawn at runtime. You write code that loads the scene and calls instantiate(), but the returned value is null. Your code might look something like this:

var enemy_scene = load("res://scenes/Enemy.tscn")
var enemy = enemy_scene.instantiate()
add_child(enemy)

When you run this, you get one of two outcomes. Either the game crashes with Invalid call. Nonexistent function 'instantiate' in base 'Nil', which means enemy_scene itself is null. Or enemy_scene loads fine but instantiate() returns null, which is rarer but happens when the scene file is corrupted or has unresolved dependencies.

If you are porting from Godot 3, you might also be calling instance() instead of instantiate(), which produces a method-not-found error since the API was renamed in Godot 4.

What Causes This

There are three primary causes for this problem, and they are worth understanding individually because the fix differs for each one.

Incorrect resource path. The most common cause by far. Godot’s resource paths are case-sensitive on all platforms, even if your operating system is not. If your file is named enemy.tscn but your code references Enemy.tscn, it will work on Windows during development and break on Linux export builds. The load() function returns null silently when the path does not match any file.

Using instance() instead of instantiate(). Godot 4 renamed PackedScene.instance() to PackedScene.instantiate() as part of a broader API cleanup. If you are following a Godot 3 tutorial or porting an older project, every call to instance() needs to be updated. The editor will show an error, but it can be easy to miss in a large project.

The scene file has missing dependencies. If your .tscn file references scripts, textures, or other resources that have been moved or deleted, the scene can fail to load entirely. Godot will print warnings in the output panel, but these can scroll past quickly during startup. The result is that load() returns a PackedScene that cannot be instantiated, or it returns null outright.

The Fix

Start by adding a null check after every load() call. This is defensive coding that will save you hours of debugging:

var enemy_scene = load("res://scenes/enemy.tscn")
if enemy_scene == null:
    push_error("Failed to load enemy scene - check the file path")
    return

var enemy = enemy_scene.instantiate()
if enemy == null:
    push_error("Failed to instantiate enemy scene - check dependencies")
    return

add_child(enemy)

Next, verify the file path is exactly correct. Open the FileSystem dock in the Godot editor, right-click the .tscn file, and select Copy Path. Paste that directly into your code. This eliminates typos and case mismatches.

If you are migrating from Godot 3, do a project-wide search for .instance() and replace every occurrence with .instantiate():

# Godot 3 (old)
var node = scene.instance()

# Godot 4 (correct)
var node = scene.instantiate()

For scenes with complex dependencies, use preload() instead of load() when the path is known at write time. Preload resolves the resource at compile time and will throw an editor error immediately if the path is wrong:

const EnemyScene = preload("res://scenes/enemy.tscn")

func spawn_enemy():
    var enemy = EnemyScene.instantiate()
    add_child(enemy)

If you need to load scenes dynamically where the path is not known until runtime, consider using ResourceLoader.load_threaded_request() and ResourceLoader.load_threaded_get() for better error handling and non-blocking loads:

func load_scene_async(path: String) -> PackedScene:
    var err = ResourceLoader.load_threaded_request(path)
    if err != OK:
        push_error("Failed to request scene load: " + path)
        return null

    while ResourceLoader.load_threaded_get_status(path) == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
        await get_tree().process_frame

    return ResourceLoader.load_threaded_get(path)

Why This Works

The null check after load() catches the most common failure—a bad path—before it can propagate. Without this check, the null value silently passes through and only surfaces as a cryptic error when you call instantiate() or add_child() on it. By checking immediately and logging the failure, you turn a mystery bug into a clear, actionable error message.

Using preload() instead of load() shifts the error from runtime to edit time. The Godot editor parses preload() paths when the script is loaded, so a bad path shows up as a red error in the script editor immediately. This is the single best practice for any scene reference that does not change at runtime.

The instance() to instantiate() rename was part of Godot 4’s effort to make the API more consistent with standard programming terminology. The old name still exists in documentation and tutorials, which is why this trips up so many developers during migration.

Related Issues

If your scenes load correctly but share state in unexpected ways, see Fix: Godot Resource Sharing Unintended State Between Instances for how exported resources can be shared across instances by default.

If your autoloaded scenes or singletons are not accessible from other scripts, check Fix: Godot Autoload/Singleton Not Accessible from Other Scripts for common configuration mistakes.

Check the path. Check the method name. Check for null. In that order.