ppy/osu · error · InvalidOperationException

Use override with HitType parameter instead

Error message

Use override with HitType parameter instead

What it means

DrumSampleTriggerSource overrides the parameterless Play() method to throw InvalidOperationException because this trigger source must know whether a hit was a Rim (whistle) or Centre (finish) hit to select the correct drum sample. The class provides a Play(HitType) overload instead. Calling the inherited parameterless Play() is a programming error.

Source

Thrown at osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs:59

                return;

            var baseSample = hitObject.CreateHitSampleInfo(hitType == HitType.Rim ? HitSampleInfo.HIT_CLAP : HitSampleInfo.HIT_NORMAL);

            if (strong)
            {
                PlaySamples(new ISampleInfo[]
                {
                    baseSample,
                    hitObject.CreateHitSampleInfo(hitType == HitType.Rim ? HitSampleInfo.HIT_WHISTLE : HitSampleInfo.HIT_FINISH)
                });
            }
            else
            {
                PlaySamples(new ISampleInfo[] { baseSample });
            }
        }

        public override void Play() => throw new InvalidOperationException(@"Use override with HitType parameter instead");

        protected override void ApplySampleInfo(SkinnableSound hitSound, ISampleInfo[] samples)
        {
            base.ApplySampleInfo(hitSound, samples);

            hitSound.Balance.Value = -0.05 + RNG.NextDouble(0.1);
        }
    }

    public enum SampleBalance
    {
        Left,
        Centre,
        Right
    }
}

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Call the Play(HitType) overload: drumSampleTriggerSource.Play(hitType).
  2. If working through a base HitSampleTriggerSource reference, cast to DrumSampleTriggerSource or resolve the HitType before calling.
  3. If polymorphic dispatch is unavoidable, check the runtime type and branch to the correct overload.

Example fix

// before — base reference, parameterless Play
HitSampleTriggerSource source = GetTriggerSource();
source.Play(); // throws if source is DrumSampleTriggerSource

// after — use the HitType overload
if (source is DrumSampleTriggerSource drumSource)
    drumSource.Play(hitType);
else
    source.Play();
Defensive patterns

Strategy: type-guard

Validate before calling

// Check the concrete type before calling Play
if (triggerSource is DrumSampleTriggerSource drumSource)
    drumSource.Play(hitType);
else
    triggerSource.Play();

Type guard

static bool RequiresHitTypeParameter(HitSampleTriggerSource source)
    => source is DrumSampleTriggerSource;

Prevention

When it happens

Trigger: Calling drumSampleTriggerSource.Play() without a HitType argument. This commonly happens when generic code holds a reference to the base class (HitSampleTriggerSource or Drawable) and dispatches through the parameterless Play() without knowing the concrete type requires a HitType.

Common situations: Polymorphic code that calls Play() on a base HitSampleTriggerSource reference; refactoring that accidentally routes through the base method; code that was written for a non-Taiko trigger source and reused without adaptation.

Related errors


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