files-community/Files · error · IOException
File already exists.
Error message
File already exists.
What it means
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.
Source
Thrown at src/Files.App.Storage/Ftp/FtpStorageFolder.cs:134
{
using var ftpClient = GetFtpClient();
await ftpClient.EnsureConnectedAsync(cancellationToken);
var newItem = await CreateCopyOfAsync(itemToMove, overwrite, cancellationToken);
await source.DeleteAsync(itemToMove, cancellationToken);
return newItem;
}
/// <inheritdoc/>
public async Task<IChildFile> CreateFileAsync(string desiredName, bool overwrite = default, CancellationToken cancellationToken = default)
{
using var ftpClient = GetFtpClient();
await ftpClient.EnsureConnectedAsync(cancellationToken);
var newPath = $"{Id}/{desiredName}";
if (overwrite && await ftpClient.FileExists(newPath, cancellationToken))
throw new IOException("File already exists.");
using var stream = new MemoryStream();
var result = await ftpClient.UploadStream(stream, newPath, overwrite ? FtpRemoteExists.Overwrite : FtpRemoteExists.Skip, token: cancellationToken);
if (result == FtpStatus.Success)
{
// Success
return new FtpStorageFile(newPath, desiredName, this);
}
else if (result == FtpStatus.Skipped)
{
// Throw exception since flag CreationCollisionOption.GenerateUniqueName was not satisfied
throw new IOException("Couldn't generate unique name. File skipped.");
}
else
{
// File creation failed
throw new IOException("File creation failed.");View on GitHub (pinned to 68c68a58d4)
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.
Example fix
// before (FtpStorageFolder.cs:133)
if (overwrite && await ftpClient.FileExists(newPath, cancellationToken))
throw new IOException("File already exists.");
// after
if (!overwrite && await ftpClient.FileExists(newPath, cancellationToken))
throw new IOException("File already exists."); Defensive patterns
Strategy: validation
Validate before calling
// Pre-check existence before creating.
var target = $"{ftpFolder.Id}/{desiredName}";
if (await ftpClient.FileExists(target, ct))
{
if (!overwrite) throw new IOException($"{desiredName} already exists.");
// else proceed with overwrite
} Try / catch
try { await folder.CreateFileAsync(name, overwrite, ct); }
catch (IOException ex) when (ex.Message == "File already exists.")
{ /* retry with overwrite=true or a unique name */ } Prevention
- 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'.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Couldn't generate unique name. File skipped.
- File creation failed.
- Directory already exists.
- Failed to create file {remotePath}.
- Copying folders is not supported.
AI-assisted analysis of files-community/Files@68c68a58d4 (2026-08-13).
Data as JSON: /api/errors/0ce1bd3b3a5a3d40.
Report an issue: GitHub.