{"record":{"id":"04a93af88d6ee2b8","repo":"OrchardCMS/OrchardCore","slug":"cannot-move-file-oldpath-to-newpath-filesystemstore","errorCode":null,"errorMessage":"Cannot move file '{oldPath}' to '{newPath}'.","messagePattern":"Cannot move file '(.+?)' to '(.+?)'\\.","errorType":"exception","errorClass":"FileStoreException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.FileStorage.FileSystem/FileSystemStore.cs","lineNumber":271,"sourceCode":"\n            var physicalNewPath = GetPhysicalPath(newPath);\n\n            if (File.Exists(physicalNewPath) || Directory.Exists(physicalNewPath))\n            {\n                throw new FileStoreException($\"Cannot move file because the new path '{newPath}' already exists.\");\n            }\n\n            File.Move(physicalOldPath, physicalNewPath);\n\n            return Task.CompletedTask;\n        }\n        catch (FileStoreException)\n        {\n            throw;\n        }\n        catch (Exception ex)\n        {\n            throw new FileStoreException($\"Cannot move file '{oldPath}' to '{newPath}'.\", ex);\n        }\n    }\n\n    public Task CopyFileAsync(string srcPath, string dstPath)\n    {\n        try\n        {\n            var physicalSrcPath = GetPhysicalPath(srcPath);\n\n            if (!File.Exists(physicalSrcPath))\n            {\n                throw new FileStoreException($\"The file '{srcPath}' does not exist.\");\n            }\n\n            var physicalDstPath = GetPhysicalPath(dstPath);\n\n            if (File.Exists(physicalDstPath) || Directory.Exists(physicalDstPath))\n            {","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.FileStorage.FileSystem/FileSystemStore.cs#L253-L289","documentation":"Wrapped FileStoreException from FileSystemStore.MoveFileAsync: the underlying File.Move threw (I/O error, source missing, path too long, locked file). Pre-existing FileStoreExceptions such as a destination conflict are rethrown unchanged; this one wraps only unexpected filesystem-level failures during the move.","triggerScenarios":"File.Move failing due to the source being locked, cross-volume move denied, invalid mapped path, or destination created by a concurrent request between the check and the move.","commonSituations":"Antivirus locking the file on Windows; storage root on a network share with transient failures; race conditions where another request creates the destination after validation.","solutions":["Inspect InnerException for the actual IO error.","Retry the move; transient locks often clear.","Serialize concurrent moves to the same destination with a lock or queue."],"exampleFix":"// before\nawait store.MoveFileAsync(src, dst); // throws on transient lock\n// after\nfor (var i = 0; i < 3; i++)\n{\n    try { await store.MoveFileAsync(src, dst); break; }\n    catch (FileStoreException) when (i < 2) { await Task.Delay(200); }\n}","handlingStrategy":"try-catch","validationCode":"// pre-validate both paths before the move\nif (await store.GetFileInfoAsync(oldPath) is null) throw new InvalidOperationException(\"missing source\");\nif (await store.GetFileInfoAsync(newPath) is not null) throw new InvalidOperationException(\"destination taken\");","typeGuard":null,"tryCatchPattern":"try { await store.MoveFileAsync(oldPath, newPath); }\ncatch (FileStoreException ex)\n{\n    _logger.LogError(ex.InnerException, \"Move {Old} -> {New} failed\", oldPath, newPath);\n    throw;\n}","preventionTips":["Retry transient IO failures with backoff.","Keep source and destination on the same storage volume.","Lock or queue concurrent operations targeting the same path."],"tags":["filesystem","io","file-move"],"backgroundTag":"file-write-failed","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}