{"record":{"id":"0ce1bd3b3a5a3d40","repo":"files-community/Files","slug":"file-already-exists","errorCode":null,"errorMessage":"File already exists.","messagePattern":"File already exists\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/Files.App.Storage/Ftp/FtpStorageFolder.cs","lineNumber":134,"sourceCode":"\t\t{\n\t\t\tusing var ftpClient = GetFtpClient();\n\t\t\tawait ftpClient.EnsureConnectedAsync(cancellationToken);\n\n\t\t\tvar newItem = await CreateCopyOfAsync(itemToMove, overwrite, cancellationToken);\n\t\t\tawait source.DeleteAsync(itemToMove, cancellationToken);\n\n\t\t\treturn newItem;\n\t\t}\n\n\t\t/// <inheritdoc/>\n\t\tpublic async Task<IChildFile> CreateFileAsync(string desiredName, bool overwrite = default, CancellationToken cancellationToken = default)\n\t\t{\n\t\t\tusing var ftpClient = GetFtpClient();\n\t\t\tawait ftpClient.EnsureConnectedAsync(cancellationToken);\n\n\t\t\tvar newPath = $\"{Id}/{desiredName}\";\n\t\t\tif (overwrite && await ftpClient.FileExists(newPath, cancellationToken))\n\t\t\t\tthrow new IOException(\"File already exists.\");\n\n\t\t\tusing var stream = new MemoryStream();\n\t\t\tvar result = await ftpClient.UploadStream(stream, newPath, overwrite ? FtpRemoteExists.Overwrite : FtpRemoteExists.Skip, token: cancellationToken);\n\n\t\t\tif (result == FtpStatus.Success)\n\t\t\t{\n\t\t\t\t// Success\n\t\t\t\treturn new FtpStorageFile(newPath, desiredName, this);\n\t\t\t}\n\t\t\telse if (result == FtpStatus.Skipped)\n\t\t\t{\n\t\t\t\t// Throw exception since flag CreationCollisionOption.GenerateUniqueName was not satisfied\n\t\t\t\tthrow new IOException(\"Couldn't generate unique name. File skipped.\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// File creation failed\n\t\t\t\tthrow new IOException(\"File creation failed.\");","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/files-community/Files/blob/68c68a58d4d6a5f7197e07c8fff85cfd4279c78b/src/Files.App.Storage/Ftp/FtpStorageFolder.cs#L116-L152","documentation":"Thrown by FtpStorageFolder.CreateFileAsync when the target file already exists. NOTE: the guard condition appears INVERTED. The code reads `if (overwrite && await ftpClient.FileExists(...))`, so it throws precisely when overwrite is true and the file exists - the opposite of the intended overwrite semantics. With the default overwrite=false, an existing file is NOT caught here and instead falls through to produce a different error via the Skipped result.","triggerScenarios":"Calling CreateFileAsync(name, overwrite: true) on an FtpStorageFolder when a file with that name already exists at {Id}/{desiredName}. Transiently hit through MoveFromAsync -> CreateCopyOfAsync -> CreateFileAsync with overwrite propagated.","commonSituations":"Copy/paste of a file whose name already exists at the destination; automated sync tools that retry with overwrite=true; test fixtures that leave files behind between runs.","solutions":["Fix the inverted condition in FtpStorageFolder.cs:133 to `if (!overwrite && await ftpClient.FileExists(newPath, cancellationToken))` so existence is only fatal when overwrite is not requested.","Before calling CreateFileAsync, check existence and choose overwrite/unique-name handling at the call site.","Catch IOException with this message and retry with overwrite=true only if overwriting is actually desired."],"exampleFix":"// before (FtpStorageFolder.cs:133)\nif (overwrite && await ftpClient.FileExists(newPath, cancellationToken))\n    throw new IOException(\"File already exists.\");\n\n// after\nif (!overwrite && await ftpClient.FileExists(newPath, cancellationToken))\n    throw new IOException(\"File already exists.\");","handlingStrategy":"validation","validationCode":"// Pre-check existence before creating.\nvar target = $\"{ftpFolder.Id}/{desiredName}\";\nif (await ftpClient.FileExists(target, ct))\n{\n    if (!overwrite) throw new IOException($\"{desiredName} already exists.\");\n    // else proceed with overwrite\n}","typeGuard":null,"tryCatchPattern":"try { await folder.CreateFileAsync(name, overwrite, ct); }\ncatch (IOException ex) when (ex.Message == \"File already exists.\")\n{ /* retry with overwrite=true or a unique name */ }","preventionTips":["Track the inverted-logic bug at FtpStorageFolder.cs:133 and fix it.","Pre-check FileExists at the call site for deterministic collision handling.","Treat overwrite=true as 'replace', not 'fail if exists'."],"tags":["ftp","storage","logic-bug","file-creation"],"backgroundTag":null,"analyzedSha":"68c68a58d4d6a5f7197e07c8fff85cfd4279c78b","analyzedAt":"2026-08-13T10:34:54.614Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}