ppy/osu · error · InvalidOperationException
Cannot Begin a scale operation while another is in progress!
Error message
Cannot Begin a scale operation while another is in progress!
What it means
OsuSelectionScaleHandler.Begin() initiates a scale operation: it snapshots original hit-object states (via OriginalHitObjectState), computes the surrounding quad and convex hull, and starts a change-handler transaction. Calling Begin when OperationInProgress.Value is already true would overwrite the snapshots and start a nested transaction.
Source
Thrown at osu.Game.Rulesets.Osu/Edit/OsuSelectionScaleHandler.cs:88
private void updateState()
{
var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects);
CanScaleX.Value = Precision.DefinitelyBigger(quad.Width, 0);
CanScaleY.Value = Precision.DefinitelyBigger(quad.Height, 0);
CanScaleDiagonally.Value = CanScaleX.Value && CanScaleY.Value;
CanScaleFromPlayfieldOrigin.Value = selectedMovableObjects.Any();
IsScalingSlider.Value = selectedMovableObjects.Count() == 1 && selectedMovableObjects.First() is Slider;
}
private Dictionary<OsuHitObject, OriginalHitObjectState>? objectsInScale;
private Vector2? defaultOrigin;
private List<Vector2>? originalConvexHull;
public override void Begin()
{
if (OperationInProgress.Value)
throw new InvalidOperationException($"Cannot {nameof(Begin)} a scale operation while another is in progress!");
base.Begin();
changeHandler?.BeginChange();
objectsInScale = selectedMovableObjects.ToDictionary(ho => ho, ho => new OriginalHitObjectState(ho));
OriginalSurroundingQuad = GeometryUtils.GetSurroundingQuad(objectsInScale.Keys);
originalConvexHull = GeometryUtils.GetConvexHull(objectsInScale.Keys);
defaultOrigin = GeometryUtils.MinimumEnclosingCircle(originalConvexHull).Item1;
}
public override void Update(Vector2 scale, Vector2? origin = null, Axes adjustAxis = Axes.Both, float axisRotation = 0)
{
if (!OperationInProgress.Value)
throw new InvalidOperationException($"Cannot {nameof(Update)} a scale operation without calling {nameof(Begin)} first!");
Debug.Assert(objectsInScale != null && defaultOrigin != null && OriginalSurroundingQuad != null);
View on GitHub (pinned to d9c73e12ad)
Solutions
- Check OperationInProgress.Value before calling Begin().
- Ensure every Begin() has a matching Commit() in the same interaction lifecycle.
- Route all scale input through a single handler to prevent concurrent Begin calls.
Example fix
// before
scaleHandler.Begin(); // may double-fire
// after
if (!scaleHandler.OperationInProgress.Value)
scaleHandler.Begin(); Defensive patterns
Strategy: validation
Validate before calling
// Guard Begin against double-entry
if (scaleHandler.OperationInProgress.Value)
return;
scaleHandler.Begin(); Prevention
- Always check OperationInProgress.Value before calling Begin().
- Map Begin to a single discrete input event and Commit to its counterpart.
- Add tests for concurrent input scenarios.
When it happens
Trigger: Calling Begin() when OperationInProgress.Value is already true — for example, a scale handle's mouse-down event firing twice without an intervening mouse-up/Commit.
Common situations: Double-binding of a scale gesture handler; concurrent input from multiple sources; state machine that doesn't enforce single-operation discipline.
Related errors
- Cannot Update a scale operation without calling Begin first!
- Cannot Commit a rotate operation without calling Begin first
- Cannot Begin a rotate operation while another is in progress
- Cannot Update a rotate operation without calling Begin first
- Cannot Commit a rotate operation without calling Begin first
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/8d47474e00143726.
Report an issue: GitHub.