ppy/osu · error · InvalidOperationException

Cannot Commit a rotate operation without calling Begin first

Error message

Cannot Commit a rotate operation without calling Begin first!

What it means

OsuSelectionScaleHandler.Commit() ends the change-handler transaction and nulls the scale state. Without a preceding Begin(), there is no open transaction to end. NOTE: The exception message says 'rotate operation' but the class is OsuSelectionScaleHandler — this is a copy-paste bug in the codebase; the message should say 'scale operation'. The underlying issue is the same lifecycle violation as the rotation handler.

Source

Thrown at osu.Game.Rulesets.Osu/Edit/OsuSelectionScaleHandler.cs:133

                scaleSlider(slider, scale, actualOrigin, objectsInScale[slider], axisRotation);
            }
            else
            {
                scale = ClampScaleToPlayfieldBounds(scale, actualOrigin, adjustAxis, axisRotation);

                foreach (var (ho, originalState) in objectsInScale)
                {
                    ho.Position = GeometryUtils.GetScaledPosition(scale, actualOrigin, originalState.Position, axisRotation);
                }
            }

            moveSelectionInBounds();
        }

        public override void Commit()
        {
            if (!OperationInProgress.Value)
                throw new InvalidOperationException($"Cannot {nameof(Commit)} a rotate operation without calling {nameof(Begin)} first!");

            changeHandler?.EndChange();

            base.Commit();

            objectsInScale = null;
            OriginalSurroundingQuad = null;
            defaultOrigin = null;
        }

        private IEnumerable<OsuHitObject> selectedMovableObjects => selectedItems.Cast<OsuHitObject>()
                                                                                 .Where(h => h is not Spinner);

        private Vector2 clampScaleToAdjustAxis(Vector2 scale, Axes adjustAxis)
        {
            switch (adjustAxis)
            {
                case Axes.Y:

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Ensure Begin() is called before Commit().
  2. Guard Commit() behind an OperationInProgress.Value check.
  3. When debugging this error, note the message incorrectly says 'rotate' — the actual class is OsuSelectionScaleHandler. The fix is in the scale handler, not the rotation handler.

Example fix

// before
scaleHandler.Commit(); // no prior Begin
// (error message says 'rotate' but this is the scale handler — known copy-paste bug)

// after
if (scaleHandler.OperationInProgress.Value)
    scaleHandler.Commit();
Defensive patterns

Strategy: validation

Validate before calling

// Guard Commit against calls without a prior Begin
if (scaleHandler.OperationInProgress.Value)
    scaleHandler.Commit();

Prevention

When it happens

Trigger: Calling Commit() when OperationInProgress.Value is false — e.g., a commit event firing without a prior Begin, or the operation was already committed.

Common situations: Double-commit from duplicate event handlers; lifecycle mismatch between the UI control and the scale handler. Developers may be confused by the misleading 'rotate' message and look in the wrong handler class.

Related errors


AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13). Data as JSON: /api/errors/52f807db2512a209. Report an issue: GitHub.