Unity-Technologies/UnityCsReference · error · ArgumentException

Object to create variant from has to be a Prefab root

Error message

Object to create variant from has to be a Prefab root

What it means

PrefabUtility.CreateVariant checks that the provided assetRoot is the root of its prefab (assetRoot.transform.root.gameObject == assetRoot) and throws ArgumentException('Object to create variant from has to be a Prefab root') otherwise. Variants must be created from the top-level GameObject of the prefab file; passing a child object within the prefab hierarchy is not allowed.

Source

Thrown at Editor/Mono/Prefabs/PrefabUtility.bindings.cs:234

        // Resets the properties of all objects in the prefab, including child game objects and components that were added to the prefab instance
        [NativeMethod("RevertPrefabInstance", IsFreeFunction = true)]
        extern private static bool RevertPrefabInstance_Internal([NotNull] GameObject go);

        // Helper function to find the prefab root of an object
        [FreeFunction]
        [Obsolete("Use GetOutermostPrefabInstanceRoot if source is a Prefab instance or source.transform.root.gameObject if source is a Prefab Asset object.")]
        extern public static GameObject FindPrefabRoot([NotNull] GameObject source);

        internal static GameObject CreateVariant(GameObject assetRoot, string path)
        {
            if (assetRoot == null)
                throw new ArgumentNullException("The inputObject is null");

            if (!IsPartOfPrefabAsset(assetRoot))
                throw new ArgumentException("Given input object is not a prefab asset");

            if (assetRoot.transform.root.gameObject != assetRoot)
                throw new ArgumentException("Object to create variant from has to be a Prefab root");

            if (path == null)
                throw new ArgumentNullException("The path is null");

            var assetRootObjectPath = AssetDatabase.GetAssetPath(assetRoot);
            if (Paths.AreEqual(path, assetRootObjectPath, true))
                throw new ArgumentException("Creating a variant of an object into the source file of the input object is not allowed");

            if (!Paths.IsValidAssetPath(path, ".prefab"))
                throw new ArgumentException("Given path is not valid: '" + path + "'");

            return CreateVariant_Internal(assetRoot, path);
        }

        [NativeMethod("CreateVariant", IsFreeFunction = true)]
        extern private static GameObject CreateVariant_Internal([NotNull] GameObject original, string path);

        [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)]

View on GitHub (pinned to 225b0fbdb5)

Solutions

  1. Navigate to the prefab root before calling CreateVariant: assetRoot = assetRoot.transform.root.gameObject
  2. If starting from a child, use go.transform.root.gameObject to get the root
  3. Verify with PrefabUtility.GetOutermostPrefabInstanceRoot or check that the object has no parent in the prefab hierarchy

Example fix

// before
var variant = PrefabUtility.CreateVariant(childObject, "Assets/Variant.prefab");

// after
GameObject root = childObject.transform.root.gameObject;
if (PrefabUtility.IsPartOfPrefabAsset(root) && root.transform.root.gameObject == root)
    var variant = PrefabUtility.CreateVariant(root, "Assets/Variant.prefab");
Defensive patterns

Strategy: validation

Validate before calling

GameObject root = assetRoot.transform.root.gameObject;
if (root != assetRoot)
{
    Debug.LogError("CreateVariant requires the prefab root, not a child object.");
    return;
}
// Safe to call CreateVariant(root, path)

Type guard

static bool IsPrefabRoot(GameObject go) =>
    go != null && PrefabUtility.IsPartOfPrefabAsset(go) && go.transform.root.gameObject == go;

Try / catch

try { var variant = PrefabUtility.CreateVariant(assetRoot, path); }
catch (ArgumentException ex) when (ex.Message == "Object to create variant from has to be a Prefab root")
{ Debug.LogError($"{assetRoot.name} is not the prefab root. Use transform.root.gameObject."); }

Prevention

When it happens

Trigger: Calling CreateVariant with a child GameObject of a prefab asset (e.g., a nested component or sub-object) instead of the prefab's root. Code that passes a specific child found via transform.Find or GetComponentInChildren without navigating to the root first.

Common situations: Editor tools that operate on a user-selected child object within a prefab. Code that searches for a specific component and then tries to create a variant from the component's GameObject. Prefab nesting where the code mistakenly grabs a nested prefab child.

Related errors


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