Unity-Technologies/UnityCsReference · error · ArgumentNullException

prefabAssetRoot

Error message

prefabAssetRoot

What it means

Thrown by ThrowIfInvalidArgumentsForReplacePrefabInstance when prefabAssetRoot is null. This is the second null guard (after prefabInstanceRoot), ensuring both the instance and the replacement asset are non-null before proceeding to the detailed asset-validity checks.

Source

Thrown at Editor/Mono/Prefabs/PrefabUtility.cs:2243

                throw new ArgumentException("Input Prefab asset is not an asset object. Input asset: " + prefabAsset.name, nameof(prefabAsset));

            var assetPath = AssetDatabase.GetAssetPath(prefabAsset);
            if (assetPath.StartsWith("Library/"))
                throw new InvalidOperationException(string.Format("Cannot replace the Prefab instance since the Prefab Asset is invalid for instance replacement. Prefab Asset path: " + assetPath));

            // Recording undo does not handle missing scripts
            var gameObjectsWithInvalidScript = FindGameObjectsWithInvalidComponent(prefabAsset);
            if (action == InteractionMode.UserAction && gameObjectsWithInvalidScript.Count > 0)
                throw new InvalidOperationException(string.Format($"Cannot replace the Prefab instance with the Prefab Asset '{AssetDatabase.GetAssetPath(prefabAsset)}' because it has a missing script. GameObject '{gameObjectsWithInvalidScript[0].name}' in the Prefab Asset has a missing script."));
        }

        internal static void ThrowIfInvalidArgumentsForReplacePrefabInstance(GameObject prefabInstanceRoot, GameObject prefabAssetRoot, bool checkValidAsset, InteractionMode mode)
        {
            if (prefabInstanceRoot == null)
                throw new ArgumentNullException(nameof(prefabInstanceRoot));

            if (prefabAssetRoot == null)
                throw new ArgumentNullException(nameof(prefabAssetRoot));

            if (checkValidAsset)
                ThrowIfInvalidAssetForReplacePrefabInstance(prefabAssetRoot, mode);

            if (!IsPartOfNonAssetPrefabInstance(prefabInstanceRoot))
                throw new InvalidOperationException(string.Format("Input '{0}' is not a Prefab instance, for plain GameObjects use ConvertToPrefabInstance() instead", prefabInstanceRoot.name));

            if (!IsOutermostPrefabInstanceRoot(prefabInstanceRoot))
                throw new ArgumentException("Input instance is not an outermost Prefab instance root. Input instance: " + prefabInstanceRoot.name, nameof(prefabInstanceRoot));
            if (EditorUtility.IsPersistent(prefabInstanceRoot))
                throw new ArgumentException("Input instance root is from a Prefab asset, this is not supported. Input instance: " + prefabInstanceRoot.name, nameof(prefabInstanceRoot));

            if (PrefabStageUtility.IsGameObjectThePrefabRootInAnyPrefabStage(prefabInstanceRoot))
                throw new InvalidOperationException("Replacing the root Prefab instance in a Variant is not supported since it will break all overrides for existing instances of this Variant, including their positions and rotations." + prefabInstanceRoot.name);
            if (IsAnyPrefabInstanceRoot(prefabInstanceRoot) && EditorSceneManager.IsPreviewSceneObject(prefabInstanceRoot) && prefabInstanceRoot.transform.parent == null) // EditPrefabContentsScope handling
                throw new InvalidOperationException("Replacing the Variant parent is not supported since it will break all overrides for existing instances of this Variant, including their positions and rotations." + prefabInstanceRoot.name);
            if (prefabInstanceRoot.transform.GetType() != prefabAssetRoot.transform.GetType())
                throw new InvalidOperationException(string.Format("Cannot replace the Prefab instance '{0}' with root transform of type {1} with a Prefab asset with root transform of type {2}. Transform types must match.", prefabInstanceRoot.name, prefabInstanceRoot.transform.GetType().Name, prefabAssetRoot.transform.GetType().Name));

View on GitHub (pinned to 225b0fbdb5)

Solutions

  1. Null-check prefabAssetRoot before calling the replace API.
  2. Validate the asset path string and existence with AssetDatabase.LoadAssetAtPath before calling.
  3. Re-resolve the asset after any AssetDatabase.Refresh.

Example fix

// before
GameObject assetRoot = AssetDatabase.LoadAssetAtPath<GameObject>(path);
ThrowIfInvalidArgumentsForReplacePrefabInstance(instanceRoot, assetRoot, true, mode);
// after
GameObject assetRoot = AssetDatabase.LoadAssetAtPath<GameObject>(path);
if (assetRoot == null) { Debug.LogError("Missing asset: " + path); return; }
ThrowIfInvalidArgumentsForReplacePrefabInstance(instanceRoot, assetRoot, true, mode);
Defensive patterns

Strategy: type-guard

Validate before calling

if (prefabAssetRoot == null)
{ Debug.LogError("prefabAssetRoot is null; verify the asset path."); return; }
PrefabUtility.ThrowIfInvalidArgumentsForReplacePrefabInstance(instanceRoot, prefabAssetRoot, checkValidAsset, mode);

Type guard

static bool AreReplaceArgsValid(GameObject instance, GameObject asset) =>
    instance != null && asset != null;

Prevention

When it happens

Trigger: Calling ReplacePrefabInstance (internal) with prefabAssetRoot == null, usually from a failed asset lookup or an unassigned reference.

Common situations: AssetDatabase.LoadAssetAtPath returned null. A serialized Prefab reference was not assigned. The asset was renamed or moved between lookup and the replace call.

Related errors


AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13). Data as JSON: /api/errors/d8e138800b6a0c6d. Report an issue: GitHub.