{"record":{"id":"a6a35e6c36810560","repo":"dotnet/wpf","slug":"sr-readnotsupported-versionedstreamowner","errorCode":null,"errorMessage":"SR.ReadNotSupported","messagePattern":"SR\\.ReadNotSupported","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/VersionedStreamOwner.cs","lineNumber":378,"sourceCode":"        }\n\n        /// <summary>\n        /// Load and compare feature identifier\n        /// </summary>\n        /// <remarks>There is no need for this method to maintain any previous Seek pointer.\n        /// This method only modifies the stream position when called for the first time with a non-empty\n        /// stream.  It is always called from Seek() and set_Position, which subsequently modify the stream\n        /// pointer as appropriate after the call.</remarks>\n        private void EnsureParsed()\n        {\n            // empty stream cannot have a version in it\n            if ((_fileVersion == null) && (BaseStream.Length > 0))\n            {\n                Debug.Assert(_dataOffset == 0);\n\n                // if no version was found and we cannot read from it, then the format is invalid\n                if (!BaseStream.CanRead)\n                    throw new NotSupportedException(SR.ReadNotSupported);\n\n                //\n                // The physical stream begins with a header that identifies the transform to\n                // which the stream belongs. The \"logical\" stream object handed to us by the\n                // compound file begins -after- this stream header, so when we seek to the\n                // \"beginning\" of this stream, we are actually seeking to the location after\n                // the stream header, where the instance data starts.\n                //\n                BaseStream.Seek(0, SeekOrigin.Begin);\n\n                //\n                // The instance data starts with format version information for this transform.\n                //\n                _fileVersion = FormatVersion.LoadFromStream(BaseStream);\n\n                //\n                // Ensure that the feature name is as expected.\n                //","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/VersionedStreamOwner.cs#L360-L396","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the underlying stream/package with FileAccess.Read or FileAccess.ReadWrite instead of Write-only.","Check stream.CanRead before constructing/using the VersionedStreamOwner.","If the stream is intentionally empty (new file), ensure Length == 0 so the parse path is skipped.","Wrap access in try-catch for NotSupportedException and surface a clearer 'open with read access' error to users."],"exampleFix":"// before\nvar stream = new FileStream(path, FileMode.Open, FileAccess.Write);\nvar vs = new VersionedStreamOwner(stream, ...);\n// after\nvar stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);\nif (!stream.CanRead) throw new InvalidOperationException(\"Stream must be readable\");\nvar vs = new VersionedStreamOwner(stream, ...);","handlingStrategy":"validation","validationCode":"public static void EnsureReadable(Stream s, string paramName = \"stream\")\n{\n    if (s == null) throw new ArgumentNullException(paramName);\n    if (!s.CanRead && s.Length > 0)\n        throw new ArgumentException(\"Stream must be readable to parse an existing compound-file version header\", paramName);\n}","typeGuard":"bool IsReadableStream(Stream s) => s != null && s.CanRead;","tryCatchPattern":"try { owner.ReadAttempt(buffer, 0, len); }\ncatch (NotSupportedException e) { throw new InvalidDataException(\"Open the package with read access; the stream is write-only\", e); }","preventionTips":["Always open packages with FileAccess.Read or ReadWrite","Assert CanRead before constructing packaging streams","Treat empty (Length == 0) streams as the only write-only-acceptable case"],"tags":["wpf","packaging","stream","read-access","io"],"backgroundTag":"unsupported-operation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}