dotnet/wpf · error · IOException
SR.PackagingWriteableDelegateGaveNullPart
Error message
SR.PackagingWriteableDelegateGaveNullPart
What it means
WriteableOnDemandPackagePart.WriteableStreamFactory asks a user-supplied delegate (_getWriteablePartInstance) for the actual PackagePart to write into, and the delegate returned null. The library throws IOException because it cannot proceed with a lazy writeable part without a concrete backing part.
Solutions
- Fix the _getWriteablePartInstance delegate so it always returns a valid PackagePart or throws a descriptive exception instead of returning null.
- Verify the underlying package is still open and the part Uri/access requested are valid when the delegate runs.
- Guard the write path: only write to the on-demand stream after confirming the delegate can produce the part.
Example fix
// before
PackagePart GetWritablePart(WriteableOnDemandPackagePart p)
{
if (_package == null) return null; // causes IOException
return _package.GetPart(p.Uri);
}
// after
PackagePart GetWritablePart(WriteableOnDemandPackagePart p)
{
if (_package == null)
throw new IOException("Package already closed; cannot create writeable part for " + p.Uri);
return _package.GetPart(p.Uri);
} Defensive patterns
Strategy: validation
Validate before calling
if (_package == null || _package.FileOpenAccess != FileAccess.ReadWrite)
throw new IOException("Package must be open for ReadWrite before writeable part can be created."); Type guard
bool CanProvideWritablePart(Func<PackagePart> factory) { try { return factory?.Invoke() != null; } catch { return false; } } Try / catch
try { stream.Write(data, 0, data.Length); }
catch (IOException ex) when (ex.Message.Contains("WriteableDelegate"))
{ Log.Error("Part delegate returned null", ex); } Prevention
- Never return null from the get-writeable-part delegate; throw with context instead.
- Keep the package open for the lifetime of on-demand parts.
- Unit-test the delegate against closed/disposed package states.
When it happens
Trigger: Calling Write/SetLength on a WriteableOnDemandPackagePart's stream triggers EnsureWritable -> _writeableStreamFactory(mode, access); the registered delegate callback returns null instead of a PackagePart instance.
Common situations: Custom XPS document assembly/deferred-save code where the delegate that instantiates the real part fails to find or create the part (e.g. part already disposed, package closed, delegate logic returning null on error paths instead of throwing).
Related errors
- SR.PackagingWriteableDelegateGaveNullStream
- SR.PackagingCircularReference
- SR.PackagingCircularReference
- SR.ReadNotSupported
- ' ' cannot contain the path delimiter: ' '.
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9ecee4291a479767.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/Documents/Application/WriteableOnDemandPackagePart.cs:192
/// <param name="mode">Desired FileMode.</param>
/// <param name="access">Desired FileAccess.</param>
/// <returns>A writeable stream.</returns>
private Stream WriteableStreamFactory(
FileMode mode,
FileAccess access)
{
if (!_isActiveWriteable)
{
Trace.SafeWrite(
Trace.Packaging,
"Creating a writeable stream for {0} with {1} access",
_activePart.Uri,
access);
PackagePart writingPart = _getWriteablePartInstance(this);
if (writingPart == null)
{
throw new IOException(
SR.PackagingWriteableDelegateGaveNullPart);
}
if (writingPart.Equals(this))
{
throw new IOException(
SR.PackagingCircularReference);
}
_activePart = writingPart;
_isActiveWriteable = true;
}
return _activePart.GetStream(mode, access);
}
#endregion Private Methods
#region Private FieldsView on GitHub (pinned to 81131a70a4)