Unity-Technologies/UnityCsReference · error · IOException

Failed to delete directory '{0}'.

Error message

Failed to delete directory '{0}'.

What it means

ReplaceDirectory ensures the destination is empty by deleting it first, then copying src into it. If the delete returns false (the native DeleteFileOrDirectory failed — locked, permissions, partial), ReplaceDirectory throws System.IO.IOException with the formatted directory path, halting before the copy. It is fail-loud by design so a half-replaced directory is never produced.

Source

Thrown at Editor/Mono/FileUtil.bindings.cs:169

        private static extern string ReadAllTextInternal(string path);

        // Replaces a file.
        public static void ReplaceFile(string src, string dst)
        {
            if (File.Exists(dst))
                FileUtil.DeleteFileOrDirectory(dst);

            FileUtil.CopyFileOrDirectory(src, dst);
        }

        // Replaces a directory.
        public static void ReplaceDirectory(string src, string dst)
        {
            if (Directory.Exists(dst))
            {
                bool succesfullyDeletedDirectory = FileUtil.DeleteFileOrDirectory(dst);
                if (succesfullyDeletedDirectory == false)
                    throw new System.IO.IOException(string.Format(
                        "Failed to delete directory '{0}'.", dst));
            }
            FileUtil.CopyFileOrDirectory(src, dst);
        }

        /// <summary>
        /// Returns the absolute path and resolves physical location for the specified path if path points to Unity Virtual File System.
        /// </summary>
        /// <remarks>The method is equivalent to Path.GetFullPath(FileUtil.GetPhysicalPath(path)), but takes into account Unity and platform path separators.</remarks>
        /// <param name="path">The file or directory for which to obtain absolute path information.</param>
        /// <returns>The fully qualified location of path. Path separators are Unity path separators ('/')</returns>
        /// <example>
        /// public class MyImporter : ScriptedImporter
        /// {
        ///     public override void OnImportAsset(AssetImportContext ctx)
        ///     {
        ///         var data = File.ReadAllText(FileUtil.PathToAbsolutePath(ctx.assetPath));
        ///         Object objectToUse = null;

View on GitHub (pinned to 225b0fbdb5)

Solutions

  1. Ensure nothing is holding files in dst open (close the editor, exclude the path from AV).
  2. Clear read-only attributes on dst contents before replacing.
  3. Catch IOException, log which path failed, and surface the OS error rather than retrying blindly.
  4. If the destination must be replaced idempotently, delete with retries/back-off before calling ReplaceDirectory.

Example fix

// before
FileUtil.ReplaceDirectory(src, dst);
// after
try { FileUtil.ReplaceDirectory(src, dst); }
catch (System.IO.IOException ex) { Debug.LogError($"could not replace {dst}: {ex.Message}"); throw; }
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-clear read-only flags and ensure nothing holds dst open.
foreach (var f in Directory.GetFiles(dst, "*", SearchOption.AllDirectories))
    File.SetAttributes(f, FileAttributes.Normal);
FileUtil.ReplaceDirectory(src, dst);

Try / catch

try { FileUtil.ReplaceDirectory(src, dst); }
catch (System.IO.IOException ex)
{ Debug.LogError($"replace failed for {dst}: {ex.Message}"); throw; }

Prevention

When it happens

Trigger: ReplaceDirectory(src, dst) where dst is an existing directory that cannot be deleted: files inside are locked by the editor or another process, permissions are insufficient, or a file is read-only on Windows.

Common situations: Re-running a ReplaceDirectory over a target that the editor or antivirus currently holds open. Replacing a directory containing read-only/version-controlled files. Replacing Library subfolders while assets are imported.

Related errors


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