dotnet/wpf · error · NotSupportedException
Streams for exposure as ILockBytes must be seekable.
Error message
Streams for exposure as ILockBytes must be seekable.
What it means
UnsafeLockBytesOnStream wraps a Stream to expose it as an ILockBytes for native compound-file APIs. The underlying stream must support seeking (random access); a non-seekable stream (e.g. network stream, pipe, or a forward-only stream) causes NotSupportedException with the 'Streams for exposure as ILockBytes must be seekable' message.
Solutions
- Wrap the non-seekable stream in a seekable buffer: copy it into a MemoryStream or a temp FileStream before creating the compound file.
- Verify stream.CanSeek before constructing, and fail fast with a clear error if false.
- For long content, spool to disk (FileStream) rather than holding it all in memory.
Example fix
// before
var package = Package.Open(nonSeekableNetworkStream);
// after
using (var buffered = new MemoryStream()) {
nonSeekableNetworkStream.CopyTo(buffered);
buffered.Position = 0;
var package = Package.Open(buffered);
} Defensive patterns
Strategy: validation
Validate before calling
if (!underlyingStream.CanSeek) throw new ArgumentException(nameof(underlyingStream), "stream must be seekable to back ILockBytes");
Try / catch
try { CreateOnStream(stream); }
catch (NotSupportedException ex) { /* buffer into MemoryStream/FileStream and retry */ } Prevention
- Check stream.CanSeek before any compound-file/Package API
- Buffer network or crypto streams into MemoryStream/FileStream first
- Prefer FileStream or MemoryStream sources for compound files
When it happens
Trigger: Passing a non-seekable Stream (CanSeek == false) — such as an unbuffered network stream, stdin/stdout wrapper, or decompression stream — into UnsafeLockBytesOnStream / UnsafeNativeCompoundFileCommon.CreateOnStream.
Common situations: Opening a Package/ZipPackage directly over an HTTP response stream or crypto stream without buffering it into a MemoryStream or FileStream first.
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
- SR.WriteNotSupported
- Stream does not support SetLength.
- Stream does not support writing.
- A read or write operation references a location outside the…
- Cannot access Stream object because it was closed or…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/950224e92f8e2f34.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/PrivateUnsafeNativeCompoundFileMethods.cs:71
int grfMode, // Specifies the access mode for opening the storage object
int stgfmt, // Specifies the storage file format, 5 is DocFile
int grfAttrs, // Reserved; must be zero
IntPtr pStgOptions,// Pointer to STGOPTIONS, not marshalled, must use NULL.
IntPtr reserved2, // Reserved; must be null
ref Guid riid, // Specifies the GUID of the interface pointer
out UnsafeNativeIStorage ppObjectOpen //Pointer to an interface pointer
);
[DllImport("ole32.dll")]
internal static extern int PropVariantClear(ref PROPVARIANT pvar);
internal class UnsafeLockBytesOnStream : UnsafeNativeILockBytes, IDisposable
{
internal UnsafeLockBytesOnStream( Stream underlyingStream )
{
if( !underlyingStream.CanSeek )
{
throw new NotSupportedException(
SR.ILockBytesStreamMustSeek);
}
_baseStream = underlyingStream;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool)
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{View on GitHub (pinned to 81131a70a4)