{"record":{"id":"ba1d1286924c267d","repo":"files-community/Files","slug":"failed-to-move-file-from-path-to-destfolder","errorCode":null,"errorMessage":"Failed to move file from {Path} to {destFolder}.","messagePattern":"Failed to move file from (.+?) to (.+?)\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/Files.App/Utils/Storage/StorageItems/FtpStorageFile.cs","lineNumber":206,"sourceCode":"\t\t\t=> MoveAsync(destinationFolder, desiredNewName, NameCollisionOption.FailIfExists);\n\t\tpublic override IAsyncAction MoveAsync(IStorageFolder destinationFolder, string desiredNewName, NameCollisionOption option)\n\t\t{\n\t\t\treturn AsyncInfo.Run((cancellationToken) => SafetyExtensions.WrapAsync(async () =>\n\t\t\t{\n\t\t\t\tusing var ftpClient = GetFtpClient();\n\t\t\t\tif (!await ftpClient.EnsureConnectedAsync())\n\t\t\t\t\tthrow new IOException($\"Failed to connect to FTP server.\");\n\n\t\t\t\tBaseStorageFolder destFolder = destinationFolder.AsBaseStorageFolder();\n\n\t\t\t\tif (destFolder is FtpStorageFolder ftpFolder)\n\t\t\t\t{\n\t\t\t\t\tstring destName = $\"{ftpFolder.FtpPath}/{Name}\";\n\t\t\t\t\tFtpRemoteExists ftpRemoteExists = option is NameCollisionOption.ReplaceExisting ? FtpRemoteExists.Overwrite : FtpRemoteExists.Skip;\n\n\t\t\t\t\tbool isSuccessful = await ftpClient.MoveFile(FtpPath, destName, ftpRemoteExists, cancellationToken);\n\t\t\t\t\tif (!isSuccessful)\n\t\t\t\t\t\tthrow new IOException($\"Failed to move file from {Path} to {destFolder}.\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow new NotSupportedException();\n\t\t\t}, ((IPasswordProtectedItem)this).RetryWithCredentialsAsync));\n\t\t}\n\n\n\t\tpublic override IAsyncAction CopyAndReplaceAsync(IStorageFile fileToReplace) => throw new NotSupportedException();\n\t\tpublic override IAsyncAction MoveAndReplaceAsync(IStorageFile fileToReplace) => throw new NotSupportedException();\n\n\t\tpublic override IAsyncAction RenameAsync(string desiredName)\n\t\t\t=> RenameAsync(desiredName, NameCollisionOption.FailIfExists);\n\t\tpublic override IAsyncAction RenameAsync(string desiredName, NameCollisionOption option)\n\t\t{\n\t\t\treturn AsyncInfo.Run((cancellationToken) => SafetyExtensions.WrapAsync(async () =>\n\t\t\t{\n\t\t\t\tusing var ftpClient = GetFtpClient();\n\t\t\t\tif (!await ftpClient.EnsureConnectedAsync())","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/files-community/Files/blob/68c68a58d4d6a5f7197e07c8fff85cfd4279c78b/src/Files.App/Utils/Storage/StorageItems/FtpStorageFile.cs#L188-L224","documentation":"Thrown by FtpStorageFile.MoveAsync when AsyncFtpClient.MoveFile returns false after a successful connection. The RNFR/RNTO rename did not complete: the destination already exists with skip mode, the source path no longer exists, the user lacks permission, or the server rejected the rename.","triggerScenarios":"MoveFile returning false inside MoveAsync. With NameCollisionOption other than ReplaceExisting, FtpRemoteExists.Skip is used, so an existing destination file causes the move to be skipped/rejected. Permission denied, source-not-found, or cross-device rename restrictions also produce false.","commonSituations":"Moving a file onto a name that already exists without choosing ReplaceExisting; the source file was deleted between listing and move; insufficient write permission at the destination; renaming across different FTP roots the server does not allow.","solutions":["If overwriting is intended, call MoveAsync with NameCollisionOption.ReplaceExisting so FtpRemoteExists.Overwrite is used.","Pre-check the destination with DirectoryExists/FileExists and resolve collisions (rename, skip, or overwrite) at the call site.","Inspect the FluentFTP reply (LastReply) for the 5xx code explaining why MoveFile failed.","Verify the source FtpPath still exists immediately before the move.","Catch IOException, confirm whether a destination collision is the cause, and retry accordingly."],"exampleFix":"// before\nawait file.MoveAsync(destFolder, file.Name, NameCollisionOption.FailIfExists);\n\n// after\nvar option = await DestExists(destFolder, file.Name)\n    ? NameCollisionOption.ReplaceExisting\n    : NameCollisionOption.FailIfExists;\nawait file.MoveAsync(destFolder, file.Name, option);","handlingStrategy":"try-catch","validationCode":"// Resolve destination collisions before moving.\nbool exists = await ftpClient.FileExists($\"{ftpFolder.FtpPath}/{file.Name}\", ct);\nvar option = exists ? NameCollisionOption.ReplaceExisting : NameCollisionOption.FailIfExists;","typeGuard":null,"tryCatchPattern":"try { await file.MoveAsync(destFolder, file.Name, option); }\ncatch (IOException ex) when (ex.Message.Contains(\"Failed to move file\"))\n{ var reply = ftpClient.LastReply; /* inspect 5xx */ throw; }","preventionTips":["Pre-check destination existence and choose ReplaceExisting when overwriting.","Confirm the source path still exists immediately before moving.","Inspect LastReply to distinguish collision from permission denial."],"tags":["ftp","storage","move","collision"],"backgroundTag":null,"analyzedSha":"68c68a58d4d6a5f7197e07c8fff85cfd4279c78b","analyzedAt":"2026-08-13T10:34:54.614Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}