{"record":{"id":"9a59e9cd2fa3cbbf","repo":"dotnet/wpf","slug":"sr-packagingcircularreference","errorCode":null,"errorMessage":"SR.PackagingCircularReference","messagePattern":"SR\\.PackagingCircularReference","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/Documents/Application/WriteableOnDemandPackagePart.cs","lineNumber":198,"sourceCode":"    {\n        if (!_isActiveWriteable)\n        {\n            Trace.SafeWrite(\n                Trace.Packaging,\n                \"Creating a writeable stream for {0} with {1} access\",\n                _activePart.Uri,\n                access);\n\n            PackagePart writingPart = _getWriteablePartInstance(this);\n            if (writingPart == null)\n            {\n                throw new IOException(\n                    SR.PackagingWriteableDelegateGaveNullPart);\n            }\n\n            if (writingPart.Equals(this))\n            {\n                throw new IOException(\n                    SR.PackagingCircularReference);\n            }\n\n            _activePart = writingPart;\n            _isActiveWriteable = true;\n        }\n\n        return _activePart.GetStream(mode, access);\n    }\n    #endregion Private Methods\n\n    #region Private Fields\n    //--------------------------------------------------------------------------\n    // Private Fields\n    //--------------------------------------------------------------------------\n\n    /// <summary>\n    /// The current comparee of this proxy.","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/Documents/Application/WriteableOnDemandPackagePart.cs#L180-L216","documentation":"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.","triggerScenarios":"Writing to a WriteableOnDemandPackagePart whose _getWriteablePartInstance delegate returns the same WriteableOnDemandPackagePart instance it was asked about.","commonSituations":"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).","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."],"exampleFix":"// before\nPackagePart GetWritablePart(WriteableOnDemandPackagePart p) => _package.GetPart(p.Uri); // resolves to p itself\n// after\nPackagePart GetWritablePart(WriteableOnDemandPackagePart p) => _package.GetPart(GetBackingUri(p.Uri)); // distinct storage part","handlingStrategy":"validation","validationCode":"PackagePart target = ResolveBackingPart(activePart);\nif (ReferenceEquals(target, activePart))\n    throw new InvalidOperationException(\"Backing part must differ from the active on-demand part.\");","typeGuard":"bool IsDistinctPart(PackagePart requested, PackagePart returned) => !ReferenceEquals(returned, requested);","tryCatchPattern":"try { stream.Write(data, 0, data.Length); }\ncatch (IOException ex) when (ex.Message.Contains(\"CircularReference\"))\n{ Log.Error(\"Part delegate returned the wrapper part itself\", ex); }","preventionTips":["Map wrapper Uris to distinct storage Uris.","Assert non-self return in the delegate during development.","Keep wrapper and storage part types distinguishable."],"tags":["wpf","packaging","circular-reference","io"],"backgroundTag":"internal-invariant-violation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}