dotnet/wpf · error · InvalidOperationException

SR.UndoServiceDisabled

Error message

SR.UndoServiceDisabled

What it means

UndoManager.Open throws this InvalidOperationException when the undo service is disabled (IsEnabled is false) but a caller tries to open a parent undo unit. The undo manager only accepts new open units while enabled, so any Open call after Disable() or during a disabled state fails fast.

Solutions

  1. Check UndoManager.IsEnabled before calling Open and skip or re-enable as appropriate
  2. Re-enable undo via UndoManager.Enable() (or set TextBox.IsUndoEnabled=true) before editing operations
  3. Audit code paths that call Disable() and ensure they re-enable before further edits

Example fix

// before
undoManager.Open(parentUnit);
// after
if (undoManager.IsEnabled)
{
    undoManager.Open(parentUnit);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!undoManager.IsEnabled) { /* skip or re-enable before Open */ }

Try / catch

try { undoManager.Open(unit); } catch (InvalidOperationException ex) when (ex.Message.Contains("disabled")) { /* undo disabled: handle gracefully */ }

Prevention

When it happens

Trigger: Calling Open (directly or via Do, Reopen, OpenCompositionUndoUnit, OpenTypingUndoUnit, or ResizeColumn such as TextBoxBase/TextBox editing) while UndoManager.IsEnabled is false.

Common situations: Text editing operations performed after code called UndoManager.Disable() (e.g. IsUndoEnabled=false on a TextBox), or an undo unit callback running while the undo stack was reset/disabled mid-composition.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/97813f805dd98228. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/UndoManager.cs:190

        /// Add the given parent undo unit to the undo manager, making it the OpenedUnit of the
        /// innermost open parent unit (or the undo manager itself, if no parents are open).
        /// </summary>
        /// <param name="unit">
        /// parent unit to add
        /// </param>
        /// <exception cref="InvalidOperationException">
        /// Thrown if UndoManager is disabled or passed unit is already open.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// Thrown if passed unit is null.
        /// </exception>
        internal void Open(IParentUndoUnit unit)
        {
            IParentUndoUnit deepestOpen;

            if (!IsEnabled)
            {
                throw new InvalidOperationException(SR.UndoServiceDisabled);
            }

            ArgumentNullException.ThrowIfNull(unit);

            deepestOpen = DeepestOpenUnit;
            if (deepestOpen == unit)
            {
                throw new InvalidOperationException(SR.UndoUnitCantBeOpenedTwice);
            }

            if (deepestOpen == null)
            {
                if (unit != LastUnit)
                {
                    // Don't want to add the unit again if we're just reopening it
                    Add(unit as IUndoUnit);
                    SetLastUnit(unit as IUndoUnit);
                }

View on GitHub (pinned to 81131a70a4)