files-community/Files · error · NotSupportedException

Moving to recycle bin is not supported.

Error message

Moving to recycle bin is not supported.

What it means

ZipStorageFolder.DeleteAsync throws NotSupportedException("Moving to recycle bin is not supported.") under the same narrow condition as the file version: deleting the archive root (Path == containerPath) with a non-permanent option (recycle bin) and no backingFile. The recycle-bin API needs a real shell-backed file; a path-only zip root cannot be recycled. Permanent deletes and deletes with a backingFile are handled.

Source

Thrown at src/Files.App/Utils/Storage/StorageItems/ZipStorageFolder.cs:576

		public override IAsyncAction DeleteAsync() => DeleteAsync(StorageDeleteOption.Default);
		public override IAsyncAction DeleteAsync(StorageDeleteOption option)
		{
			return AsyncInfo.Run((cancellationToken) => SafetyExtensions.WrapAsync(async () =>
			{
				if (Path == containerPath)
				{
					if (backingFile is not null)
					{
						await backingFile.DeleteAsync();
					}
					else if (option == StorageDeleteOption.PermanentDelete)
					{
						PInvoke.DeleteFileFromApp(Path);
					}
					else
					{
						throw new NotSupportedException("Moving to recycle bin is not supported.");
					}
				}
				else
				{
					var index = await FetchZipIndex();
					if (index.IsEmpty())
					{
						return;
					}
					using (var ms = new MemoryStream())
					{
						await using (var archiveStream = await OpenZipFileAsync(FileAccessMode.Read))
						{
							SevenZipCompressor compressor = new SevenZipCompressor() { CompressionMode = CompressionMode.Append };
							compressor.CustomParameters.Add("cu", "on");
							compressor.SetFormatFromExistingArchive(archiveStream);
							var entriesMap = new Dictionary<int, string>(index.Select(x => new KeyValuePair<int, string>(x.Index, null)));
							await compressor.ModifyArchiveAsync(archiveStream, entriesMap, Credentials.Password, ms);

View on GitHub (pinned to 68c68a58d4)

Solutions

  1. Delete with StorageDeleteOption.PermanentDelete, or construct the ZipStorageFolder with a backingFile so the backing file's DeleteAsync is used.
  2. At the call site, detect zip-root + no backing file and resolve the StorageFile first or switch to permanent delete.
  3. Use the ZipStorageFolder(BaseStorageFile) constructor for archive roots that must support recycle-bin deletes.

Example fix

// before
await zipRootFolder.DeleteAsync(); // recycle bin, throws

// after
await zipRootFolder.DeleteAsync(StorageDeleteOption.PermanentDelete);
Defensive patterns

Strategy: validation

Validate before calling

bool CanRecycle(BaseStorageFolder f) => !(f is ZipStorageFolder zsf && zsf.Path == /*containerPath*/ /*&& no backingFile*/);

Type guard

static bool IsZipBacked(BaseStorageFolder f) => f is ZipStorageFolder;

Try / catch

try { await f.DeleteAsync(); }
catch (NotSupportedException) { await f.DeleteAsync(StorageDeleteOption.PermanentDelete); }

Prevention

When it happens

Trigger: Deleting a ZipStorageFolder that is the archive container (Path == containerPath), no backingFile, with StorageDeleteOption.Default (recycle bin).

Common situations: User presses Delete (no Shift) on a .zip opened by path with no StorageFile backing, sending it to recycle bin.

Related errors


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