{"record":{"id":"bb9710e8cfdbd82d","repo":"dotnet/wpf","slug":"sr-reachserialization-cycledetectedinserialization","errorCode":null,"errorMessage":"SR.ReachSerialization_CycleDetectedInSerialization","messagePattern":"SR\\.ReachSerialization_CycleDetectedInSerialization","errorType":"exception","errorClass":"XpsSerializationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachObjectContext.cs","lineNumber":132,"sourceCode":"        {\n            //\n            // Check for element pre-existance to avoid infinite loops\n            // in the process of serialization\n            //\n            int stackIndex = 0;\n\n            object currentObject = null;\n\n            for(currentObject = serializationManager.GraphContextStack[stackIndex];\n                currentObject != null;\n                currentObject = serializationManager.GraphContextStack[++stackIndex])\n            {\n                SerializableObjectContext currentObjectContext = currentObject as SerializableObjectContext;\n\n                if(currentObjectContext!=null &&\n                   currentObjectContext.TargetObject == serializableObject)\n                {\n                    throw new XpsSerializationException(SR.ReachSerialization_CycleDetectedInSerialization);\n                }\n            }\n\n            SerializableObjectContext serializableObjectContext;\n            lock (_stackLock)\n            {\n                serializableObjectContext =\n                    _recycableSerializableObjectContexts.Count == 0 ?\n                    null :\n                    (SerializableObjectContext)_recycableSerializableObjectContexts.Pop();\n            }\n\n            if(serializableObjectContext == null)\n            {\n                serializableObjectContext = new SerializableObjectContext(serializableObject,\n                                                                          serializablePropertyContext);\n            }\n            else","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachObjectContext.cs#L114-L150","documentation":"ReachObjectContext.CreateContext throws XpsSerializationException (ReachSerialization_CycleDetectedInSerialization) when it detects that the object about to get a new serialization context is already being serialized higher up the context stack (its TargetObject matches a current context). Serializing a cyclic object graph would loop forever or overflow the stack, so the XPS serializer fails fast. XPS documents must be tree-shaped; cycles are unsupported.","triggerScenarios":"Calling the XPS serializer on an object graph containing a reference cycle — e.g. a Visual whose Children collection (transitively) contains an ancestor, or parent/child properties pointing at each other.","commonSituations":"Reusing the same Visual/FixedPage instance in multiple places in a document; models with bidirectional parent-child references being fed straight into XpsDocumentWriter; shared resources attached into the visual tree more than once.","solutions":["Break the cycle by making the graph a strict tree before serialization (remove back-references from the serialized tree)","Clone shared sub-objects so each appears only once in the graph","Skip serializing parent references (mark them [SerializeIgnore]-like by rebuilding a serializable copy)","Catch XpsSerializationException and walk the graph for repeated references before saving"],"exampleFix":"// before\nchild.Parent = parent;   // cycle: parent.Children contains child\nwriter.Write(parent);\n// after\nvar copy = CloneForSerialization(parent); // drop Parent back-reference\nwriter.Write(copy);","handlingStrategy":"validation","validationCode":"static bool HasCycle(object root) { var seen = new HashSet<object>(); var stack = new Stack<object>(); stack.Push(root); while (stack.Count > 0) { var o = stack.Pop(); if (o == null || !seen.Add(o)) continue; foreach (var c in GetChildren(o)) stack.Push(c); } return false; } // GetChildren enumerates visual/logical children; a repeated node indicates a cycle\n","typeGuard":"static bool IsAcyclic(object root) => !ContainsReference(root, root, new HashSet<object>());","tryCatchPattern":"try { writer.Write(root); } catch (System.Windows.Xps.XpsSerializationException ex) when (ex.Message.Contains(\"cycle\")) { log.Error(\"Cyclic object graph passed to XPS writer\", ex); throw; }","preventionTips":["Never reuse the same visual instance twice in one tree","Strip parent/back-references before serializing","Clone shared subtrees into distinct instances","Add a cycle-detection walk before every XPS write"],"tags":["xps","wpf","serialization","circular-reference","dotnet"],"backgroundTag":"circular-reference-detected","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"}