dotnet/wpf · error · InvalidOperationException
SR.UndoUnitOpen
Error message
SR.UndoUnitOpen
What it means
UndoManager.Undo throws this when OpenedUnit is non-null, meaning a parent undo unit is currently open (a unit is being recorded). Undo cannot run while a unit is open because the open unit's contents are not finalized and the undo stack is in an inconsistent state.
Solutions
- Ensure every Open() has a matching Close() in a finally block so OpenedUnit returns to null before undo is requested.
- Defer Undo calls raised during recording (text-change events) until after the unit closes.
- If a unit was left open by an exception, close/reset the manager to clear OpenedUnit before undoing.
- Do not nest user-triggered Undo inside code that is creating undo units.
Example fix
// before
undoManager.Open(unit);
MakeEdit();
undoManager.Undo(1); // throws: unit still open
undoManager.Close();
// after
undoManager.Open(unit);
try { MakeEdit(); }
finally { undoManager.Close(); }
undoManager.Undo(1); Defensive patterns
Strategy: validation
Validate before calling
if (undoManager.OpenedUnit == null && undoManager.State == UndoState.Normal) { undoManager.Undo(1); } Type guard
static bool CanUndoNow(UndoManager m) => m.OpenedUnit == null && m.State == UndoState.Normal;
Prevention
- Close open units in finally blocks
- Defer undo requested during unit recording
- Recover leaked open units promptly
When it happens
Trigger: Calling Undo(count) between Open(parentUnit) and Close() — e.g. undo invoked from a text-change event fired while an edit unit is being recorded, or leaked open unit from an exception that skipped Close.
Common situations: Programmatic edits wrapped in open undo units while also invoking the Undo command; a prior exception in unit recording left the unit open forever, breaking all later Undo calls; automated tests doing 'type text then undo' without closing recording scopes.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.UndoNoOpenParentUnit
- SR.Format(SR.BindingExpressionStatusChanged, _status…
- SR.Format(SR.CannotCallRunMultipleTimes…
- SR.ShutdownModeWhenAppShutdown
- SR.Storyboard_NeverApplied
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/ca4acc18a59bc83a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs:519
/// </exception>
internal void Undo(int count)
{
if (!IsEnabled)
{
throw new InvalidOperationException(SR.UndoServiceDisabled);
}
ArgumentOutOfRangeException.ThrowIfGreaterThan(count, UndoCount);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count);
if (State != UndoState.Normal)
{
throw new InvalidOperationException(SR.UndoNotInNormalState);
}
if (OpenedUnit != null)
{
throw new InvalidOperationException(SR.UndoUnitOpen);
}
Invariant.Assert(UndoCount > _minUndoStackCount);
SetState(UndoState.Undo);
bool exceptionThrown = true;
try
{
while (count > 0)
{
IUndoUnit unit;
unit = PopUndoStack();
unit.Do();
count--;
}View on GitHub (pinned to 81131a70a4)