files-community/Files · error · IOException

File creation failed.

Error message

File creation failed.

What it means

Thrown by FtpStorageFolder.CreateFileAsync when UploadStream returns a status that is neither Success nor Skipped - i.e. FtpStatus.Failed. This indicates FluentFTP could not complete the upload of the empty MemoryStream to {Id}/{desiredName}. Causes are server-side: permission denied, path does not exist, quota exceeded, or a broken/terminated control or data connection.

Source

Thrown at src/Files.App.Storage/Ftp/FtpStorageFolder.cs:152

				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.");
			}
		}

		/// <inheritdoc/>
		public async Task<IChildFolder> CreateFolderAsync(string desiredName, bool overwrite = default, CancellationToken cancellationToken = default)
		{
			using var ftpClient = GetFtpClient();
			await ftpClient.EnsureConnectedAsync(cancellationToken);

			var newPath = $"{Id}/{desiredName}";
			if (overwrite && await ftpClient.DirectoryExists(newPath, cancellationToken))
				throw new IOException("Directory already exists.");

			var isSuccessful = await ftpClient.CreateDirectory(newPath, overwrite, cancellationToken);
			if (!isSuccessful)
				throw new IOException("Directory was not successfully created.");

			return new FtpStorageFolder(newPath, desiredName, this);

View on GitHub (pinned to 68c68a58d4)

Solutions

  1. Inspect the FluentFTP log (FtpTrace or a custom logger) for the underlying 4xx/5xx reply to determine the real server-side cause.
  2. Verify the FTP account has write permission and available quota on the target folder.
  3. Ensure the parent directory exists before creating the file.
  4. Retry on transient failures with backoff; surface a clearer message mapping the FluentFTP reply code to the user.
  5. Switch to an active-mode or alternate PASV port range if data-channel setup is failing.

Example fix

// before
var result = await ftpClient.UploadStream(stream, newPath, existsMode, token: cancellationToken);
if (result != FtpStatus.Success && result != FtpStatus.Skipped)
    throw new IOException("File creation failed.");

// after - capture the last reply for diagnostics
var reply = ftpClient.LastReply;
throw new IOException($"File creation failed: {(int)reply.Code} {reply.Message}");
Defensive patterns

Strategy: retry

Validate before calling

// Verify writability of the target before the upload.
if (!await ftpClient.FileExists(folder.Id, ct)) { /* ensure parent exists */ }

Try / catch

for (int attempt = 0; attempt < 3; attempt++)
try { return await folder.CreateFileAsync(name, overwrite, ct); }
catch (IOException ex) when (ex.Message == "File creation failed." && attempt < 2)
{ await Task.Delay(TimeSpan.FromSeconds(1 << attempt)); }
throw new IOException("File creation failed after retries.");

Prevention

When it happens

Trigger: UploadStream returning FtpStatus.Failed during CreateFileAsync. Typical when the parent directory is missing, the FTP user lacks write permission on the target folder, disk/quota limits are hit, or the connection dropped mid-transfer.

Common situations: Read-only or quota-capped FTP accounts; uploading into a path that was never created; TLS/data-port firewall rules that intermittently break PASV transfers; anti-virus blocking zero-byte file creation on the server.

Related errors


AI-assisted analysis of files-community/Files@68c68a58d4 (2026-08-13). Data as JSON: /api/errors/4ec59bfe6dc5fd68. Report an issue: GitHub.