"Parent directory not in asset database" Error Despite Creating Folder

Hello! I am working on a small programme created to scan all assets in a Unity project and relocate them to their correct directories if they are misplaced, however I’m stuck due to a persistent problem “Parent directory is not in asset database” in my Unity Editor script. This occurs whenever I use AssetDatabase.MoveAsset, even though I’m taking steps to proactively create the folder.

What I’ve done:

  • Folder Creation: Using Directory.CreateDirectory or custom methods built upon AssetDatabase.CreateFolder.
  • Asset Import: Calling AssetDatabase.ImportAsset with the ImportAssetOptions.ImportRecursive flag.
  • Asset Database Refresh: Frequent use of AssetDatabase.Refresh.

Snippet (Illustrative):

public class AssetData
    {
        public string Path { get; private set; }
        public string Name { get; private set; }
        public string SuggestedPath { get; private set; }
        public string FileExtension
        {
            get { return System.IO.Path.GetExtension(Path).ToLower(); }
        }
        public bool IsModified { get; set; } = false;

        public AssetData(string path, string name, string suggestedPath)
        {
            Path = path;
            Name = name;
            SuggestedPath = suggestedPath;
        }
     
    }
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

[ExecuteInEditMode]
public class AssetProcesser : MonoBehaviour
{
    private Queue<AssetData> m_assetsToProcess;


   // Here List<AssetData> assets has one element and it's value is..
   // asset.Name = "Ground"
   // assets.Path = "Assets/Prefab/Ground.mat"
   // asset.SuggestedPath = "Assets/NewMaterial/Ground.mat"
 





    public void CorrectAssets(List<AssetData> assets)
    {
        m_assetsToProcess = new Queue<AssetData>(assets);
        EditorApplication.update += ProcessAssetCorrectionQueue;
        AssetDatabase.StartAssetEditing();
    }

    private void ProcessAssetCorrectionQueue()
    {
        if (m_assetsToProcess.Count == 0)
        {
            FinishAssetCorrection();
            return;
        }

        try
        {
            foreach (AssetData asset in m_assetsToProcess)
            {
                ProcessAsset(asset);
            }
        }
        finally
        {
           FinishAssetCorrection();
        }
    }

    private void ProcessAsset(AssetData asset)
    {
        string guid = AssetDatabase.AssetPathToGUID(asset.Path);
        string currentPath = AssetDatabase.GUIDToAssetPath(guid);
        string newPath = asset.SuggestedPath;

        string newParentDirectory = Path.GetDirectoryName(newPath);
        CreateFolderIfNeeded(newParentDirectory);
        ImportFolderRecursive(newParentDirectory);
        AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive);

        string
            error = AssetDatabase.MoveAsset(currentPath,
                newPath); // Error I am getting : Parent directory is not in asset database

        if (!string.IsNullOrEmpty(error))
        {
            ToolsLogs.LogError($"Failed to rename asset {asset.Path}: {error}");
        }

        AssetDatabase.ImportAsset(newPath, ImportAssetOptions.ImportRecursive);
    }

    private static void CreateFolderIfNeeded(string folderPath)
    {
        if (!folderPath.StartsWith("Assets/"))
        {
            ToolsLogs.LogError("Invalid path. Path must be within the Assets folder.");
            return;
        }

        string[] folders = folderPath.Substring("Assets/".Length).Split('/');
        string currentPath = "Assets";

        if (!AssetDatabase.IsValidFolder(folderPath))
        {
            try
            {
                for (int i = 0; i < folders.Length; i++)
                {
                    string folderName = folders[i];
                    currentPath = Path.Combine(currentPath, folderName);

                    if (AssetDatabase.IsValidFolder(currentPath))
                    {
                        continue;
                    }

                    string createdFolderGuid = AssetDatabase.CreateFolder(Path.GetDirectoryName(currentPath),
                        Path.GetFileName(currentPath));

                    if (!string.IsNullOrEmpty(createdFolderGuid))
                    {
                        AssetDatabase.ImportAsset(currentPath, ImportAssetOptions.ImportRecursive);
                        Debug.Log($"Created folder: {createdFolderGuid}");
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error creating directory: {ex.Message}");
            }
        }
    }

    private static void ImportFolderRecursive(string folderPath)
    {
        AssetDatabase.ImportAsset(folderPath,
            ImportAssetOptions.ImportRecursive | ImportAssetOptions.ForceSynchronousImport);
    }

    private void FinishAssetCorrection()
    {
        EditorUtility.ClearProgressBar();
        EditorApplication.update -= ProcessAssetCorrectionQueue;
        AssetDatabase.Refresh();
    }
}

here this

Things I’ve Tried:

  • Debugging with Logs: I’ve verified the folder exists on the file system, but the Asset Database doesn’t recognize it.
  • Forced Delays: Tried add delay but no help.
  • Alternative Folder Creation: Experimented with other folder creation methods(Directory.CreateDirectory)

Questions:

  • What are the typical reasons the Asset Database might lag in recognizing new folders?
  • Are there more reliable ways to force synchronization between the file system and the Asset Database?
  • Could other aspects of my asset processing script be causing interference?

Environment:

  • Unity Version: [2021.3.15f1]
  • Operating System: [macOS]

Additional Notes:

  • I’m open to exploring meta file issues if basic solutions don’t work.
  • The script executes only within the Unity Editor (not at runtime). The code provided is simplified.

Thanks in advance for any guidance!

I guess the most obvious question is, “Is newPath reasonable?” Print it out!

If not that then just make hard-wired Dir1 and Dir2 and issue the move command until it works for that… the weird lumps and oddnesses of the Unity asset database API can surprise you where some stuff requires “Assets/” and some stuff doesn’t, etc.

Not only that but during different phases of the import, it wouldn’t surprise me if certain files are not movable at that moment. The asset importer thing is pretty … strict.

CorrectAssets isn’t called in the code shown. This makes it impossible to say whether ProcessAssetCorrectionQueue has StartAssetEditing called before entering that method. And then, even if it is, if you trigger this early out clause:

     if (m_assetsToProcess.Count == 0)
        {
            FinishAssetCorrection();
            return;
        }

… then … when is StopAssetEditing being called? I guess it simply isn’t, thus you are leaving the AssetDatabase in stopped state and no imports or refreshes occur until you restart the editor!

StartAssetEditing belongs either on the line before try or it’s the first line within the try clause, anything else spells trouble.

Next, while you can call ImportAsset (or Refresh, whose correct name should really be: ImportAllAssets) within a Start/StopAssetEditing, it simply has no effect. The asset will only be imported when StopAssetEditing runs. If you do ImportAsset and then LoadAsset within a Start/StopAssetEditing block you will always get a null return value, regardless of whether the asset exists or not.

This is why the CreateFolderIfNeeded is broken because the imported folders are still not in the database, despite importing them. Check my implementation of CreateFoldersIfNeeded, it’s well-tested.

Since all you do is moving assets, check my Asset.File.Move implementation. It’s just two lines: creating the folders, and calling MoveAsset. You don’t need to import an asset that has been moved, you can be assured that AssetDatabase methods properly update the database state for any operation they perform.

Lastly, the Refresh at the end is unnecessary. If you don’t call it, and there’s still assets not being refreshed in the project view, then you simply forgot to import some of the assets. Otherwise, if all System.IO operations have a corresponding ImportAsset there’s simply nothing to refresh.

Replace the second line with this:
var currentPath = asset.Path;

If you read those two lines again you’ll notice why. :wink:

CorrectAssets[quote=“Kurt-Dekker, post:2, topic: 943314, username:Kurt-Dekker”]
I guess the most obvious question is, “Is newPath reasonable?” Print it out!

If not that then just make hard-wired Dir1 and Dir2 and issue the move command until it works for that… the weird lumps and oddnesses of the Unity asset database API can surprise you where some stuff requires “Assets/” and some stuff doesn’t, etc.

Not only that but during different phases of the import, it wouldn’t surprise me if certain files are not movable at that moment. The asset importer thing is pretty … strict.
[/quote]

@Kurt-Dekker , thank you for your suggestion regarding the newPath variable. You make a fair point, and I should have provided more details initially.

Let me explain the purpose of the program I’m working on a small tool that scans all assets in a Unity project and moves them to the correct directory if they are misplaced.

The program takes a list of “AssetData” objects as input. Each object contains the current path of an asset and the suggested path where it should be moved. For instance, I have a material asset currently in the “Prefabs” folder, which is incorrect. The suggested path is “Assets/Materials/NewDirectory”.

In this case, the “NewDirectory” folder doesn’t exist yet under “Assets/Materials”. Program will calls “CreateFolderIfNeeded” method, which successfully creates “NewDirectory” on the file system (I can see it in the file explorer).

However, when I attempt to move the material asset using “AssetDatabase.MoveAsset”, it giving me this error “Parent directory is not in asset database” error. Curiously, this error occurs even though the “NewDirectory” folder has been successfully created on the file system, indicating a potential synchronization issue between the file system and Unity’s Asset Database.

I’ve tried calling “AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive)” and “AssetDatabase.ImportAsset(currentPath, ImportAssetOptions.ImportRecursive)” after folder creation, but the issue persists, suggesting that the Asset Database is still not recognizing the newly created folder.

Thank you for the suggestion, @Kurt-Dekker . To prevent any confusion for others, I will update the original thread based on your recommendations.

Thanks a lot, @CodeSmile , for your thorough analysis and suggestions! I really appreciate your attention to detail.

While CorrectAssets isn’t explicitly called in the code snippet provided, I can confirm through debugging that it is indeed called and executes as expected. I’ll make sure to explicitly handle StartAssetEditing and StopAssetEditing to ensure proper asset editing sessions.

I also noticed the mistake in the finally block and have already updated it to call the FinishAssetCorrection method. My apologies for any confusion caused.

Regarding your implementation suggestions, I’ll review them. My main concern is preserving asset references even after moving them, so I’ll need to ensure that any changes made won’t affect these references.

Once again, thank you for taking the time to share your insights and help!

1 Like

Asset references will not break by using MoveAsset. References only break if the asset GUID changes, eg if you were to copy the asset and delete the original you‘d get broken references.

That makes sense! Thanks for the clear explanation, this solves my problem!