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

  1. Make the delegate return a distinct backing PackagePart, never the WriteableOnDemandPackagePart instance passed in.
  2. If redirecting by Uri, ensure the target Uri differs from the active part's Uri.
  3. 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

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


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)