Unity-Technologies/UnityCsReference · error · ArgumentException
GameObject to save Prefab from must be a Prefab root
Error message
GameObject to save Prefab from must be a Prefab root
What it means
SavePrefabAsset operates on whole prefabs, so the supplied asset must be the root of its prefab. If asset.transform.root.gameObject != asset, the caller passed a non-root child and ArgumentException is thrown. The method then forwards the root to the internal save routine.
Source
Thrown at Editor/Mono/Prefabs/PrefabUtility.cs:2033
public static GameObject SavePrefabAsset(GameObject asset, out bool savedSuccessfully)
{
if (asset == null)
throw new ArgumentNullException("Parameter prefabAssetGameObject is null");
// Include model check even though models are also immutable, since we can give a more clear exception message.
if (IsPartOfModelPrefab(asset))
throw new ArgumentException("Can't save a Model Prefab");
if (IsPartOfImmutablePrefab(asset))
throw new ArgumentException("Can't save an immutable Prefab");
string path = AssetDatabase.GetAssetPath(asset);
if (String.IsNullOrEmpty(path))
throw new ArgumentException("Can't save a Prefab instance");
var root = asset.transform.root.gameObject;
if (root != asset)
throw new ArgumentException("GameObject to save Prefab from must be a Prefab root");
return SavePrefabAsset_Internal(root, out savedSuccessfully);
}
internal static void ValidatePath(GameObject instanceRoot, string path)
{
if (String.IsNullOrEmpty(path))
throw new ArgumentNullException("path is null or empty");
if (!Paths.IsValidAssetPath(path, ".prefab"))
throw new ArgumentException("Given path is not valid: '" + path + "'");
if (Directory.Exists(path))
throw new ArgumentException("Overwriting a folder with an Asset is not allowed: '" + path + "'");
string directory = Path.GetDirectoryName(path);
// We allow relative paths outside the Assets folder so we do not throw if isValidAssetFolder is falseView on GitHub (pinned to 225b0fbdb5)
Solutions
- Resolve the root before saving: asset = asset.transform.root.gameObject.
- Filter selection to root objects, or walk up to the root explicitly.
- Verify asset.transform.root.gameObject == asset before calling.
Example fix
// before PrefabUtility.SavePrefabAsset(childGo); // after PrefabUtility.SavePrefabAsset(childGo.transform.root.gameObject);
Defensive patterns
Strategy: validation
Validate before calling
GameObject root = asset.transform.root.gameObject; if (root != asset) asset = root;
Type guard
static bool IsPrefabRoot(GameObject asset) =>
asset != null && asset.transform.root.gameObject == asset; Prevention
- Resolve asset.transform.root.gameObject before saving.
- Filter selection to root objects, or walk up to the root explicitly.
- Verify the supplied object equals its transform root before calling.
When it happens
Trigger: Passing a child GameObject of a prefab asset rather than the prefab root.
Common situations: Selecting a child object within a prefab asset and calling save; selection logic that hands back a sub-object instead of the root.
Related errors
- ApplyAddedGameObjects requires that GameObjects share the sa
- Object is a parentless root.
- ApplyPrefabAddedGameObjects requires that GameObjects share
- PrefabFamilyPopup is already open
- guid
AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13).
Data as JSON: /api/errors/b08411f3b79e8695.
Report an issue: GitHub.