{"record":{"id":"113f1f8e118fd483","repo":"dotnet/wpf","slug":"sr-undounitalreadyopen","errorCode":null,"errorMessage":"SR.UndoUnitAlreadyOpen","messagePattern":"SR\\.UndoUnitAlreadyOpen","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs","lineNumber":246,"sourceCode":"        ///     another unit is already open\n        ///     the given unit is locked\n        ///     the given unit is not on top of the stack\n        /// </exception>\n        /// <exception cref=\"ArgumentNullException\">\n        /// Thrown if passed unit is null.\n        /// </exception>\n        internal void Reopen(IParentUndoUnit unit)\n        {\n            if (!IsEnabled)\n            {\n                throw new InvalidOperationException(SR.UndoServiceDisabled);\n            }\n\n            ArgumentNullException.ThrowIfNull(unit);\n\n            if (OpenedUnit != null)\n            {\n                throw new InvalidOperationException(SR.UndoUnitAlreadyOpen);\n            }\n\n            switch (State)\n            {\n                case UndoState.Normal:\n                case UndoState.Redo:\n                    {\n                        if (UndoCount == 0 || PeekUndoStack() != unit)\n                        {\n                            throw new InvalidOperationException(SR.UndoUnitNotOnTopOfStack);\n                        }\n\n                        break;\n                    }\n\n                case UndoState.Undo:\n                    {\n                        if (RedoStack.Count == 0 || (IParentUndoUnit)RedoStack.Peek() != unit)","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs#L228-L264","documentation":"InvalidOperationException from UndoManager.Reopen: another parent undo unit is already open on this undo stack, and only one open unit is allowed at a time (nested units must be closed or reopened via the open unit itself).","triggerScenarios":"Calling Reopen while OpenedUnit is non-null, e.g. nested OpenCompositionUndoUnit/OpenTypingUndoUnit calls without closing the previous unit first.","commonSituations":"Overlapping IME composition events, or a typing undo unit opened on top of a still-open composition unit because Close was skipped on an exception path.","solutions":["Ensure every Open/Reopen has a matching Close (including in exception paths via try/finally)","Check UndoManager.OpenedUnit for null before calling Reopen","Close the current unit with an appropriate UndoCloseAction before reopening"],"exampleFix":"// before\nundoManager.Reopen(unit);\n// after\nif (undoManager.OpenedUnit == null)\n{\n    undoManager.Reopen(unit);\n}","handlingStrategy":"validation","validationCode":"if (undoManager.OpenedUnit != null) { /* close current unit first */ }","typeGuard":null,"tryCatchPattern":"try { undoManager.Reopen(unit); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"already open\")) { /* close the open unit then retry */ }","preventionTips":["Pair every Open/Reopen with a Close in try/finally","Close open units on exception paths","Never nest Reopen calls"],"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-21T21:30:21.729Z"}