{"record":{"id":"d53adc0045c79457","repo":"dotnet/wpf","slug":"sr-undonoopenparentunit","errorCode":null,"errorMessage":"SR.UndoNoOpenParentUnit","messagePattern":"SR\\.UndoNoOpenParentUnit","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs","lineNumber":461,"sourceCode":"                            {\n                                _bottomUndoIndex = 0;\n                            }\n                        }\n                        UndoStack[_topUndoIndex] = unit;\n                    }\n                }\n                else if (State == UndoState.Undo)\n                {\n                    RedoStack.Push(unit);\n                }\n                else if (State == UndoState.Rollback)\n                {\n                    // do nothing, throwing out the unit\n                }\n            }\n            else\n            {\n                throw new InvalidOperationException(SR.UndoNoOpenParentUnit);\n            }\n        }\n\n        /// <summary>\n        /// Clear the undo and redo stacks, as well as LastUnit.\n        /// </summary>\n        /// <exception cref=\"InvalidOperationException\">\n        /// Thrown if UndoManager is disabled\n        /// </exception>\n        internal void Clear()\n        {\n            if (!IsEnabled)\n            {\n                throw new InvalidOperationException(SR.UndoServiceDisabled);\n            }\n\n            // In practice, we only clear when the public IsUndoEnabled property is set false.\n            // We'll check that property again when _imeSupportModeEnabled transitions to false.","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs#L443-L479","documentation":"UndoManager.Add throws this when the unit being added has no open parent unit to attach to (DeepestOpenUnit is null and the unit itself is not a top-level unit that can be pushed directly). Undo units must be added inside an open parent unit context; otherwise the manager cannot place them on a stack and fails fast.","triggerScenarios":"Calling Add with an IUndoUnit when no parent unit is open: e.g. calling Create*UndoUnit/Add helpers outside an Open(unit) ... Close() scope, or after the parent unit was already closed, so DeepestOpenUnit returns null.","commonSituations":"Custom IUndoUnit implementations recorded after their parent unit was closed; unbalanced Open/Close (exception skipped Close, or Close called twice); adding a unit from a different thread or re-entrant call after the open unit completed.","solutions":["Ensure a parent unit is open before Add: call Open(parentUnit) (or use the Create*UndoUnit flow that manages opening) and Close it in a finally block.","Audit Open/Close pairing — make Close run even on exceptions so the open-unit stack stays balanced.","For top-level units, use the API path designed for them instead of Add on a closed context.","Do not cache an UndoManager open-unit context across user operations; open a fresh unit per edit."],"exampleFix":"// before\nvar unit = undoManager.CreateInsertUndoUnit(...);\nundoManager.Add(unit); // throws: no open parent\n// after\nusing (new UndoScope(undoManager)) // helper that calls Open/Close in Dispose\n{\n    var unit = undoManager.CreateInsertUndoUnit(...);\n    undoManager.Add(unit);\n}","handlingStrategy":"try-catch","validationCode":"if (undoManager.IsEnabled) { /* ensure unit open scope */ }","typeGuard":null,"tryCatchPattern":"try { undoManager.Add(unit); }\ncatch (InvalidOperationException) { /* no open parent: open a scope and retry or log */ }","preventionTips":["Wrap unit recording in Open/Close scopes with finally","Never cache open-unit contexts across operations","Audit exception paths so Close is never skipped"],"tags":["wpf","undo","invalid-state","lifecycle"],"backgroundTag":"invalid-state-transition","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"}