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
- Enumerate the folder contents yourself and copy each child file individually, recreating subfolders via CreateFolderAsync.
- Type-check the source before calling: only invoke CreateCopyOfAsync when itemToCopy is IFile; otherwise fall back to a manual recursive copy.
- Surface a user-facing message that FTP folder copy is unsupported rather than letting the NotSupportedException propagate.
- 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
- Branch on IFile vs IFolder before invoking FTP copy/move.
- Do not route folder moves through MoveFromAsync; it delegates to the unsupported CreateCopyOfAsync.
- Document at the UI layer that FTP directory copy is unsupported.
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
- File already exists.
- Couldn't generate unique name. File skipped.
- File creation failed.
- Directory already exists.
- Directory was not successfully created.
AI-assisted analysis of files-community/Files@68c68a58d4 (2026-08-13).
Data as JSON: /api/errors/6c2e5e24a2f515de.
Report an issue: GitHub.