dotnet/wpf · error · IOException
SR.PackagingCircularReference
Error message
SR.PackagingCircularReference
What it means
WriteableOnDemandPackagePart.WriteableStreamFactory checks that the PackagePart returned by the delegate is not the on-demand part itself; a self-referencing part would create an infinite loop of part-to-part redirection. Equality with 'this' throws IOException with PackagingCircularReference.
Solutions
- Make the delegate return a distinct backing PackagePart, never the WriteableOnDemandPackagePart instance passed in.
- If redirecting by Uri, ensure the target Uri differs from the active part's Uri.
- Add an assertion/log in the delegate to catch self-mapping during development.
Example fix
// before PackagePart GetWritablePart(WriteableOnDemandPackagePart p) => _package.GetPart(p.Uri); // resolves to p itself // after PackagePart GetWritablePart(WriteableOnDemandPackagePart p) => _package.GetPart(GetBackingUri(p.Uri)); // distinct storage part
Defensive patterns
Strategy: validation
Validate before calling
PackagePart target = ResolveBackingPart(activePart);
if (ReferenceEquals(target, activePart))
throw new InvalidOperationException("Backing part must differ from the active on-demand part."); Type guard
bool IsDistinctPart(PackagePart requested, PackagePart returned) => !ReferenceEquals(returned, requested);
Try / catch
try { stream.Write(data, 0, data.Length); }
catch (IOException ex) when (ex.Message.Contains("CircularReference"))
{ Log.Error("Part delegate returned the wrapper part itself", ex); } Prevention
- Map wrapper Uris to distinct storage Uris.
- Assert non-self return in the delegate during development.
- Keep wrapper and storage part types distinguishable.
When it happens
Trigger: Writing to a WriteableOnDemandPackagePart whose _getWriteablePartInstance delegate returns the same WriteableOnDemandPackagePart instance it was asked about.
Common situations: Delegate implementation bug: looking up the part by Uri resolves back to the wrapper part itself instead of the real storage part (e.g. dictionary mapping the wrapper's Uri to itself).
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- SR.PackagingCircularReference
- SR.PackagingWriteableDelegateGaveNullPart
- SR.PackagingWriteableDelegateGaveNullStream
- SR.ReadNotSupported
- ' ' cannot contain the path delimiter: ' '.
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9a59e9cd2fa3cbbf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/Documents/Application/WriteableOnDemandPackagePart.cs:198
{
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 Fields
//--------------------------------------------------------------------------
// Private Fields
//--------------------------------------------------------------------------
/// <summary>
/// The current comparee of this proxy.View on GitHub (pinned to 81131a70a4)