Unity-Technologies/UnityCsReference · error · ArgumentException

Cyclic nesting detected

Error message

Cyclic nesting detected

What it means

Thrown by ValidatePath when VerifyNestingFromScript detects that saving the Prefab would create a cycle — the Prefab would end up nested inside itself, directly or transitively. This prevents infinite recursion in the Prefab hierarchy graph.

Source

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

            string directory = Path.GetDirectoryName(path);

            // We allow relative paths outside the Assets folder so we do not throw if isValidAssetFolder is false
            bool isRootFolder = false;
            bool isImmutableFolder = false;
            bool isValidAssetFolder = AssetDatabase.TryGetAssetFolderInfo(directory, out isRootFolder, out isImmutableFolder);

            if (isValidAssetFolder && isImmutableFolder)
                throw new ArgumentException("Saving Prefab to immutable folder is not allowed: '" + path + "'");

            if (directory.Length > 0 && !Directory.Exists(directory))
                throw new ArgumentException("Given path does not exist: '" + path + "'");

            if (isValidAssetFolder)
            {
                string projectRelativePath = Path.IsPathRooted(path) ? FileUtil.GetProjectRelativePath(path) : path;
                string prefabGUID = AssetDatabase.AssetPathToGUID(projectRelativePath);
                if (!VerifyNestingFromScript(new GameObject[] { instanceRoot }, prefabGUID, PrefabUtility.GetPrefabInstanceHandle(instanceRoot)))
                    throw new ArgumentException("Cyclic nesting detected");
            }
        }

        private static void SaveAsPrefabAssetArgumentCheck(GameObject instanceRoot, string path, bool connectToInstance)
        {
            if (instanceRoot == null)
                throw new ArgumentNullException("Parameter root is null");

            if (EditorUtility.IsPersistent(instanceRoot) && connectToInstance)
                throw new ArgumentException("Can't save persistent Objects and connect them to the saved Prefab");

            if (IsPartOfNonAssetPrefabInstance(instanceRoot))
            {
                // A PrefabInstance with missing asset can be correctly restored only if CorrespondingObjects info is available
                // CorrespondingObject info is available when a PrefabInstance with missing asset was merged before deleting the asset (kNormalMerge) or when it has a scene backup (kMergedAsMissingWithSceneBackup)
                var mergeStatus = GetMergeStatus(instanceRoot);
                var hasCorrespondingSourceObjectInfo = mergeStatus == MergeStatus.NormalMerge || mergeStatus == MergeStatus.MergedAsMissingWithSceneBackup;
                if (IsPrefabAssetMissing(instanceRoot) && !hasCorrespondingSourceObjectInfo)

View on GitHub (pinned to 225b0fbdb5)

Solutions

  1. Ensure the target assetPath is different from the instanceRoot's own Prefab source path.
  2. If editing a Prefab in Prefab Mode, save normally rather than calling SaveAsPrefabAsset to a path that resolves to the same asset.
  3. Inspect the hierarchy for any GameObject whose source is the same Prefab being saved and remove the self-reference.

Example fix

// before
// instanceRoot is an instance of "Assets/A.prefab"
PrefabUtility.SaveAsPrefabAsset(instanceRoot, "Assets/A.prefab");
// after
PrefabUtility.SaveAsPrefabAsset(instanceRoot, "Assets/A_variant.prefab");
Defensive patterns

Strategy: validation

Validate before calling

bool WouldCauseCycle(GameObject instanceRoot, string targetPath)
{
    string projectRelative = Path.IsPathRooted(targetPath)
        ? FileUtil.GetProjectRelativePath(targetPath) : targetPath;
    string sourceGuid = AssetDatabase.AssetPathToGUID(projectRelative);
    var handle = PrefabUtility.GetPrefabInstanceHandle(instanceRoot);
    return !PrefabUtility.VerifyNestingFromScript(
        new[] { instanceRoot }, sourceGuid, handle);
}

Type guard

static bool IsSafeNestingTarget(GameObject instanceRoot, string path) =>
    !WouldCauseCycle(instanceRoot, path);

Try / catch

try { PrefabUtility.SaveAsPrefabAsset(go, path); }
catch (ArgumentException e) when (e.Message.Contains("Cyclic nesting"))
{ Debug.LogError("Cycle detected; choose a different path."); }

Prevention

When it happens

Trigger: Saving a Prefab instance whose root is (or contains a reference back to) the same Prefab asset it corresponds to, so the resulting asset would reference itself as a parent. Occurs when the instanceRoot's prefab GUID equals the GUID of the asset at the target path, or when nested variants create a loop.

Common situations: Attempting to save a Prefab over itself from within its own open Prefab edit context. Re-parenting a Prefab under one of its own children. Working with nested Prefab variants and accidentally creating a circular reference.

Related errors


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