{"record":{"id":"e41697d505e24e2a","repo":"AvaloniaUI/Avalonia","slug":"stream-is-not-readable","errorCode":null,"errorMessage":"Stream is not readable","messagePattern":"Stream is not readable","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Media/Fonts/UnmanagedFontMemory.cs","lineNumber":167,"sourceCode":"            {\n                // Release upgradeable read lock\n                _lock.ExitUpgradeableReadLock();\n            }\n        }\n\n        /// <summary>\n        /// Loads font data from the specified stream into unmanaged memory.\n        /// </summary>\n        public static UnmanagedFontMemory LoadFromStream(Stream stream)\n        {\n            if (stream is null)\n            {\n                throw new ArgumentNullException(nameof(stream));\n            }\n\n            if (!stream.CanRead)\n            {\n                throw new ArgumentException(\"Stream is not readable\", nameof(stream));\n            }\n\n            if (stream.CanSeek)\n            {\n                var length = checked((int)stream.Length);\n                var ptr = Marshal.AllocHGlobal(length);\n                var buffer = ArrayPool<byte>.Shared.Rent(8192);\n\n                try\n                {\n                    var remaining = length;\n                    var offset = 0;\n\n                    while (remaining > 0)\n                    {\n                        var toRead = Math.Min(buffer.Length, remaining);\n                        var read = stream.Read(buffer, 0, toRead);\n","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Media/Fonts/UnmanagedFontMemory.cs#L149-L185","documentation":"UnmanagedFontMemory.LoadFromStream copies a font stream into native memory for the rasterizer to access via raw pointer. It refuses to read a stream whose CanRead is false, because it would allocate a buffer and then fail to fill it. This is a precondition check before any allocation.","triggerScenarios":"Passing a FileStream opened with FileAccess.Write; passing a MemoryStream whose CanRead was overridden to false; passing a stream that was already disposed (some streams report CanRead=false after disposal); passing a CryptoStream in write-only mode.","commonSituations":"Reusing a stream after positioning at the end and disposing inadvertently; loading a font from a NetworkStream that the underlying client has closed; wrapping a stream in a write-only adapter for serialization and then reusing it for font loading.","solutions":["Check stream.CanRead before calling LoadFromStream and surface a clear error if false.","Open the source file with FileAccess.Read (not Write or ReadWrite-with-closed-handle).","For MemoryStream, ensure it was constructed from a readable source and not disposed.","Re-open the source as a fresh read-only stream rather than reusing a write/transform stream."],"exampleFix":"// before\nvar mem = UnmanagedFontMemory.LoadFromStream(_writeOnlyStream);\n\n// after\nif (stream is null) throw new ArgumentNullException(nameof(stream));\nif (!stream.CanRead)\n    throw new ArgumentException(\"Font stream must be readable; reopen the source with FileAccess.Read.\", nameof(stream));\nvar mem = UnmanagedFontMemory.LoadFromStream(stream);","handlingStrategy":"validation","validationCode":"static Stream EnsureReadable(Stream s)\n{\n    if (s is null) throw new ArgumentNullException(nameof(s));\n    if (!s.CanRead) throw new ArgumentException(\"Stream must be readable.\", nameof(s));\n    if (s.CanSeek && s.Position != 0) s.Position = 0;\n    return s;\n}","typeGuard":"static bool IsReadable(Stream s) => s is not null && s.CanRead;","tryCatchPattern":null,"preventionTips":["Open font files with FileAccess.Read.","Do not reuse disposed or write-only streams for font loading.","Check CanRead and reset Position before LoadFromStream."],"tags":["io","stream","fonts","precondition","argument-validation"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}