ppy/osu · error · InvalidOperationException
HitObjectContainer should be set before HandleHit is called.
Error message
HitObjectContainer should be set before HandleHit is called.
What it means
StartTimeOrderedHitPolicy.HandleHit() requires HitObjectContainer to enumerate and miss all hit objects prior to the hit one. The policy must be initialized with HitObjectContainer before any hit is handled. The null check guards the enumeration inside HandleHit.
Source
Thrown at osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs:60
// 1. The last blocking hitobject has not yet been judged.
// 2. The current time is before the last hitobject's start time.
//
// Hits at exactly the same time as the blocking hitobject are allowed for maps that contain simultaneous hitobjects (e.g. /b/372245).
if (!blockingObject.Judged && time < blockingObject.HitObject.StartTime)
return ClickAction.Shake;
}
// Generally when the user has hit way too early.
if (result == HitResult.None)
return ClickAction.Shake;
return ClickAction.Hit;
}
public void HandleHit(DrawableHitObject hitObject)
{
if (HitObjectContainer == null)
throw new InvalidOperationException($"{nameof(HitObjectContainer)} should be set before {nameof(HandleHit)} is called.");
// Hitobjects which themselves don't block future hitobjects don't cause misses (e.g. slider ticks, spinners).
if (!hitObjectCanBlockFutureHits(hitObject))
return;
if (CheckHittable(hitObject, hitObject.HitObject.StartTime + hitObject.Result.TimeOffset, hitObject.Result.Type) != ClickAction.Hit)
throw new InvalidOperationException($"A {hitObject} was hit before it became hittable!");
// Miss all hitobjects prior to the hit one.
foreach (var obj in enumerateHitObjectsUpTo(hitObject.HitObject.StartTime))
{
if (obj.Judged)
continue;
if (hitObjectCanBlockFutureHits(obj))
((DrawableOsuHitObject)obj).MissForcefully();
}
}
View on GitHub (pinned to d9c73e12ad)
Solutions
- Set HitObjectContainer on the policy before any hits can be processed.
- Ensure the playfield assigns HitObjectContainer to the policy during LoadComplete, before hit objects become interactive.
Example fix
// before var policy = new StartTimeOrderedHitPolicy(); policy.HandleHit(hitObject); // HitObjectContainer is null // after var policy = new StartTimeOrderedHitPolicy(); policy.HitObjectContainer = HitObjectContainer; policy.HandleHit(hitObject);
Defensive patterns
Strategy: validation
Validate before calling
// Ensure HitObjectContainer is set before any hit can be handled
if (policy.HitObjectContainer == null)
throw new InvalidOperationException("HitObjectContainer must be set before gameplay.");
policy.HitObjectContainer = HitObjectContainer; Prevention
- Initialize StartTimeOrderedHitPolicy with HitObjectContainer during Playfield.LoadComplete.
- Ensure custom DrawableHitObject subclasses do not call HandleHit before the playfield is fully loaded.
- Add a test that verifies HandleHit works after proper initialization.
When it happens
Trigger: Calling HandleHit(hitObject) before setting HitObjectContainer on the StartTimeOrderedHitPolicy instance.
Common situations: Same as [13] — policy created without wiring the container; a custom DrawableHitObject that calls HandleHit during load before the playfield finishes setup.
Related errors
- HitObjectContainer should be set before CheckHittable is cal
- HitObjectContainer should be set before CheckHittable is cal
- A {hitObject} was hit before it became hittable!
- Can't have zero or fewer stages.
- Unsupported grid type.
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/13d95b3572338757.
Report an issue: GitHub.