dotnet/wpf · error · NotSupportedException

SR.ReadNotSupported

Error message

SR.ReadNotSupported

What it means

VersionedStreamOwner.EnsureParsed must deserialize the version header from the base stream. If no version was parsed yet, the stream is non-empty, and the stream is not readable (CanRead == false), the file format cannot be validated, so a NotSupportedException is thrown.

Solutions

  1. Open the underlying stream/package with FileAccess.Read or FileAccess.ReadWrite instead of Write-only.
  2. Check stream.CanRead before constructing/using the VersionedStreamOwner.
  3. If the stream is intentionally empty (new file), ensure Length == 0 so the parse path is skipped.
  4. Wrap access in try-catch for NotSupportedException and surface a clearer 'open with read access' error to users.

Example fix

// before
var stream = new FileStream(path, FileMode.Open, FileAccess.Write);
var vs = new VersionedStreamOwner(stream, ...);
// after
var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
if (!stream.CanRead) throw new InvalidOperationException("Stream must be readable");
var vs = new VersionedStreamOwner(stream, ...);
Defensive patterns

Strategy: validation

Validate before calling

public static void EnsureReadable(Stream s, string paramName = "stream")
{
    if (s == null) throw new ArgumentNullException(paramName);
    if (!s.CanRead && s.Length > 0)
        throw new ArgumentException("Stream must be readable to parse an existing compound-file version header", paramName);
}

Type guard

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

Try / catch

try { owner.ReadAttempt(buffer, 0, len); }
catch (NotSupportedException e) { throw new InvalidDataException("Open the package with read access; the stream is write-only", e); }

Prevention

When it happens

Trigger: Opening a VersionedStreamOwner over a non-empty stream opened for write-only access (e.g. FileAccess.Write) and performing WriteAttempt/ReadAttempt/IsUpdatable/IsReadable before any version header is parsed.

Common situations: Opening a package with FileMode.Open/Write-only access and then reading; passing a stream created from a file opened with Write-only permissions; using a network or memory stream that does not support reading.

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/a6a35e6c36810560. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/VersionedStreamOwner.cs:378

        }

        /// <summary>
        /// Load and compare feature identifier
        /// </summary>
        /// <remarks>There is no need for this method to maintain any previous Seek pointer.
        /// This method only modifies the stream position when called for the first time with a non-empty
        /// stream.  It is always called from Seek() and set_Position, which subsequently modify the stream
        /// pointer as appropriate after the call.</remarks>
        private void EnsureParsed()
        {
            // empty stream cannot have a version in it
            if ((_fileVersion == null) && (BaseStream.Length > 0))
            {
                Debug.Assert(_dataOffset == 0);

                // if no version was found and we cannot read from it, then the format is invalid
                if (!BaseStream.CanRead)
                    throw new NotSupportedException(SR.ReadNotSupported);

                //
                // The physical stream begins with a header that identifies the transform to
                // which the stream belongs. The "logical" stream object handed to us by the
                // compound file begins -after- this stream header, so when we seek to the
                // "beginning" of this stream, we are actually seeking to the location after
                // the stream header, where the instance data starts.
                //
                BaseStream.Seek(0, SeekOrigin.Begin);

                //
                // The instance data starts with format version information for this transform.
                //
                _fileVersion = FormatVersion.LoadFromStream(BaseStream);

                //
                // Ensure that the feature name is as expected.
                //

View on GitHub (pinned to 81131a70a4)