{"record":{"id":"c2e1d12ed19136c0","repo":"dotnet/wpf","slug":"sr-undounitcantbeopenedtwice-undomanager","errorCode":null,"errorMessage":"SR.UndoUnitCantBeOpenedTwice","messagePattern":"SR\\.UndoUnitCantBeOpenedTwice","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs","lineNumber":198,"sourceCode":"        /// </exception>\n        /// <exception cref=\"ArgumentNullException\">\n        /// Thrown if passed unit is null.\n        /// </exception>\n        internal void Open(IParentUndoUnit unit)\n        {\n            IParentUndoUnit deepestOpen;\n\n            if (!IsEnabled)\n            {\n                throw new InvalidOperationException(SR.UndoServiceDisabled);\n            }\n\n            ArgumentNullException.ThrowIfNull(unit);\n\n            deepestOpen = DeepestOpenUnit;\n            if (deepestOpen == unit)\n            {\n                throw new InvalidOperationException(SR.UndoUnitCantBeOpenedTwice);\n            }\n\n            if (deepestOpen == null)\n            {\n                if (unit != LastUnit)\n                {\n                    // Don't want to add the unit again if we're just reopening it\n                    Add(unit as IUndoUnit);\n                    SetLastUnit(unit as IUndoUnit);\n                }\n                SetOpenedUnit(unit);\n                unit.Container = this;\n            }\n            else\n            {\n                unit.Container = deepestOpen;\n                deepestOpen.Open(unit);\n            }","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs#L180-L216","documentation":"UndoManager.Open throws this when the unit passed is already the deepest currently open unit (deepestOpen == unit). A single unit cannot be opened twice; nested Open calls must use distinct, newly created parent units.","triggerScenarios":"Calling Open with the same IParentUndoUnit instance that is already open, typically from re-entrant calls in Do, Reopen, OpenCompositionUndoUnit, OpenTypingUndoUnit, or ResizeColumn.","commonSituations":"Re-entrant text change handlers (TextChanged/TextChanging) that open the same undo unit again, or custom code that opens a unit and then triggers an edit that re-opens it.","solutions":["Create a new IParentUndoUnit instance for each Open call instead of reusing one","Check UndoManager.OpenedUnit/DeepestOpenUnit before opening and skip if already open","Guard re-entrant event handlers with a boolean flag while the unit is open"],"exampleFix":"// before\nvar unit = _cachedUnit;\nundoManager.Open(unit);\n// after\nvar unit = new ParentUndoUnit(undoManager);\nundoManager.Open(unit);","handlingStrategy":"validation","validationCode":"if (undoManager.OpenedUnit == unit || undoManager.DeepestOpenUnit == unit) { /* already open: skip */ }","typeGuard":null,"tryCatchPattern":"try { undoManager.Open(unit); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"twice\")) { /* unit already open: reuse it */ }","preventionTips":["Create a fresh ParentUndoUnit per Open call","Guard re-entrant TextChanged handlers with a flag","Never cache and reuse opened undo units"],"tags":["wpf","undo","invalid-operation"],"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-22T01:17:13.364Z"}