dotnet/wpf · error · InvalidOperationException

SR.ReadNotSupported

Error message

SR.ReadNotSupported

What it means

CompressEmulationStream emulation requires both seek AND read on the base stream. When the base stream is seekable but not readable (CanRead == false), the constructor throws InvalidOperationException with SR.ReadNotSupported.

Solutions

  1. Open the base stream with FileAccess.Read or FileAccess.ReadWrite.
  2. Check baseStream.CanRead before constructing and fail fast with a clear message.
  3. Ensure file permissions/ACLs allow reading the underlying file.

Example fix

// before
var fs = new FileStream(path, FileMode.Open, FileAccess.Write);
var es = new CompressEmulationStream(fs, tempStream, transformer);
// after
var fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
if (!fs.CanRead) throw new InvalidOperationException("Base stream must be readable");
var es = new CompressEmulationStream(fs, tempStream, transformer);
Defensive patterns

Strategy: validation

Validate before calling

static void RequireSeekableReadable(Stream s, string paramName = "baseStream")
{
    if (s == null) throw new ArgumentNullException(paramName);
    if (!s.CanSeek) throw new ArgumentException("Base stream must be seekable", paramName);
    if (!s.CanRead) throw new ArgumentException("Base stream must be readable", paramName);
}

Type guard

bool CanEmulate(Stream s) => s != null && s.CanSeek && s.CanRead;

Try / catch

try { var es = new CompressEmulationStream(fs, temp, t); }
catch (InvalidOperationException e) { throw new UnauthorizedAccessException("Open the base stream with read or read/write access", e); }

Prevention

When it happens

Trigger: Constructing CompressEmulationStream with a baseStream opened for write-only access (FileAccess.Write) or a write-only pipe/network stream.

Common situations: Opening a package file with write-only permissions and passing the FileStream in; streams obtained from write-only sinks.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/9add1a318a3d682a. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompressEmulationStream.cs:257

        /// <param name="baseStream">part stream - not closed - caller determines lifetime</param>
        /// <param name="position">current logical stream position</param>
        /// <param name="tempStream">should be an IsolatedStorageFileStream - not closed - caller determines lifetime</param>
        /// <param name="transformer">class that does the compression/decompression</param>
        /// <remarks>This class should only invoked when emulation is required.  
        /// Does not close any given stream, even when Close is called. This means that it requires
        /// another wrapper Stream class.</remarks>
        internal CompressEmulationStream(Stream baseStream, Stream tempStream, long position, IDeflateTransform transformer)
        {
            ArgumentOutOfRangeException.ThrowIfNegative(position);

            ArgumentNullException.ThrowIfNull(baseStream);

            // seek and read required for emulation
            if (!baseStream.CanSeek)
                throw new InvalidOperationException(SR.SeekNotSupported);

            if (!baseStream.CanRead)
                throw new InvalidOperationException(SR.ReadNotSupported);

            ArgumentNullException.ThrowIfNull(tempStream);
            ArgumentNullException.ThrowIfNull(transformer);

            _baseStream = baseStream;
            _tempStream = tempStream;
            _transformer = transformer;

            // extract to temporary stream
            _baseStream.Position = 0;
            _tempStream.Position = 0;
            _transformer.Decompress(baseStream, tempStream);

            // seek to the current logical position
            _tempStream.Position = position;
        }
        #endregion

View on GitHub (pinned to 81131a70a4)