files-community/Files · error · NotSupportedException

Can't open zip file as RW

Error message

Can't open zip file as RW

What it means

In ZipStorageFile.OpenAsync, when the requested access is FileAccessMode.ReadWrite and the file is an inner zip entry (Path != containerPath, SevenZip branch), the code throws NotSupportedException("Can't open zip file as RW"). ZIP entries are extracted into a transient MemoryStream that is read-only, so the implementation cannot honor a read-write handle back into the archive.

Source

Thrown at src/Files.App/Utils/Storage/StorageItems/ZipStorageFile.cs:155

					}

					//zipFile.IsStreamOwner = true;
					var entry = zipFile.GetArchiveFileData(containerPath).FirstOrDefault(x => System.IO.Path.Combine(containerPath, x.FileName) == Path);

					if (entry.FileName is not null)
					{
						var ms = new MemoryStream();
						await zipFile.ExtractFileAsync(entry.Index, ms);
						ms.Position = 0;
						return new NonSeekableRandomAccessStreamForRead(ms, entry.Size)
						{
							DisposeCallback = () => zipFile.Dispose()
						};
					}
					return null;
				}

				throw new NotSupportedException("Can't open zip file as RW");
			}, ((IPasswordProtectedItem)this).RetryWithCredentialsAsync));
		}
		private IAsyncOperation<IRandomAccessStream> OpenWithEncodingAsync(FileAccessMode accessMode)
		{
			return AsyncInfo.Run((cancellationToken) => SafetyExtensions.Wrap<IRandomAccessStream>(async () =>
			{
				bool rw = accessMode is FileAccessMode.ReadWrite;
				if (rw)
					throw new NotSupportedException("Can't open zip file as RW");

				using var zipFile = new ZipFile(containerPath, StringCodec.FromEncoding(CurrentEncoding!));

				if (!string.IsNullOrEmpty(Credentials.Password))
					zipFile.Password = Credentials.Password;

				var targetName = GetEntryRelativePath();

				foreach (ZipEntry entry in zipFile)

View on GitHub (pinned to 68c68a58d4)

Solutions

  1. Open with FileAccessMode.Read only for inner zip entries; for editing, extract the entry to a real file and edit that.
  2. Check access mode at the call site and reject ReadWrite for archive entries before calling OpenAsync.
  3. Use CopyAsync to materialize the entry into a real BaseStorageFile, then open that for read-write.

Example fix

// before
using var stream = await zipEntryFile.OpenAsync(FileAccessMode.ReadWrite); // throws

// after
if (zipEntryFile is ZipStorageFile zf && zf.Path != /*containerPath*/) // inner entry
    throw new InvalidOperationException("Zip entries are read-only; extract first.");
using var stream = await zipEntryFile.OpenAsync(FileAccessMode.Read);
Defensive patterns

Strategy: validation

Validate before calling

bool CanOpenRw(BaseStorageFile f) => f is not ZipStorageFile zf || zf.Path == /*containerPath*/;

Type guard

static bool IsZipEntry(BaseStorageFile f) => f is ZipStorageFile;

Try / catch

try { return await f.OpenAsync(FileAccessMode.ReadWrite); }
catch (NotSupportedException) { /* fall back to read-only or extract first */ }

Prevention

When it happens

Trigger: Calling OpenAsync(FileAccessMode.ReadWrite) (or OpenAsync with the ReadWrite value) on a ZipStorageFile that represents an entry inside a ZIP (not the archive root). Also any OpenAsync(options) overload that forwards to this method with ReadWrite.

Common situations: An editor or save routine that opens a file for read-write editing directly on a zip entry, expecting in-place editing, instead of extracting first. Copy-and-edit flows that reuse the IStorageItem handle.

Related errors


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