files-community/Files · warning · NotSupportedException

Copying folders is not supported.

Error message

Copying folders is not supported.

What it means

Thrown by FtpStorageFolder.CreateCopyOfAsync when the item to copy is not an IFile (i.e. it is an IFolder). The FTP storage implementation only supports byte-stream copies of files via CopyContentsToAsync; it has no recursive directory copy. MoveFromAsync internally delegates to CreateCopyOfAsync, so attempting to move a folder into an FTP folder hits the same path.

Source

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

			else
			{
				throw new ArgumentException($"Could not delete {item}.");
			}
		}

		/// <inheritdoc/>
		public async Task<IStorableChild> CreateCopyOfAsync(IStorableChild itemToCopy, bool overwrite = default, CancellationToken cancellationToken = default)
		{
			if (itemToCopy is IFile sourceFile)
			{
				var copiedFile = await CreateFileAsync(itemToCopy.Name, overwrite, cancellationToken);
				await sourceFile.CopyContentsToAsync(copiedFile, cancellationToken);

				return copiedFile;
			}
			else
			{
				throw new NotSupportedException("Copying folders is not supported.");
			}
		}

		/// <inheritdoc/>
		public async Task<IStorableChild> MoveFromAsync(IStorableChild itemToMove, IModifiableFolder source, bool overwrite = default, CancellationToken cancellationToken = default)
		{
			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)
		{

View on GitHub (pinned to 68c68a58d4)

Solutions

  1. Enumerate the folder contents yourself and copy each child file individually, recreating subfolders via CreateFolderAsync.
  2. Type-check the source before calling: only invoke CreateCopyOfAsync when itemToCopy is IFile; otherwise fall back to a manual recursive copy.
  3. Surface a user-facing message that FTP folder copy is unsupported rather than letting the NotSupportedException propagate.
  4. For cross-provider moves, avoid MoveFromAsync for folders; implement copy-then-delete manually.

Example fix

// before
await destFolder.CreateCopyOfAsync(folderItem, overwrite, ct);

// after
if (folderItem is IFile file)
    await destFolder.CreateCopyOfAsync(file, overwrite, ct);
else if (folderItem is IFolder srcFolder)
    await CopyFolderRecursively(srcFolder, (IModifiableFolder)destFolder, ct);
else
    throw new NotSupportedException();
Defensive patterns

Strategy: type-guard

Validate before calling

// Only call CreateCopyOfAsync for files; handle folders separately.
if (itemToCopy is not IFile)
    throw new InvalidOperationException($"Cannot copy {itemToCopy?.Name}: FTP folder copy is unsupported.");
var copy = await ftpFolder.CreateCopyOfAsync(itemToCopy, overwrite, ct);

Type guard

static bool IsFtpCopyable(IStorableChild item) => item is IFile;

Try / catch

try { await dest.CreateCopyOfAsync(item, overwrite, ct); }
catch (NotSupportedException) when (item is not IFile)
{ /* fall back to recursive folder copy */ }

Prevention

When it happens

Trigger: Calling CreateCopyOfAsync on an FtpStorageFolder with an IStorableChild that is an IFolder (not IFile). Also triggered transitively by MoveFromAsync when the source item is a folder, since MoveFromAsync calls CreateCopyOfAsync then DeleteAsync.

Common situations: Drag-and-drop or copy/move UI passing a directory to an FTP destination; cross-provider copy where the source folder is not decomposed into individual file copies by the caller; generic copy code that treats files and folders uniformly without a branch.

Related errors


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