ppy/osu · error · InvalidOperationException
A {nameof(PoolableSkinnableSample)} cannot be applied multip
Error message
A {nameof(PoolableSkinnableSample)} cannot be applied multiple {nameof(ISampleInfo)}s. What it means
Thrown by PoolableSkinnableSample.Apply(ISampleInfo) when sampleInfo is already non-null, enforcing that a pooled sample is single-use: exactly one ISampleInfo may ever be applied during its lifetime. Re-applying would leave stale volume/sample state.
Source
Thrown at osu.Game/Skinning/PoolableSkinnableSample.cs:62
/// Creates a new <see cref="PoolableSkinnableSample"/> with an applied <see cref="ISampleInfo"/>.
/// </summary>
/// <param name="sampleInfo">The <see cref="ISampleInfo"/> to attach.</param>
public PoolableSkinnableSample(ISampleInfo sampleInfo)
: this()
{
Apply(sampleInfo);
}
/// <summary>
/// Applies an <see cref="ISampleInfo"/> that describes the sample to retrieve.
/// Only one <see cref="ISampleInfo"/> can ever be applied to a <see cref="PoolableSkinnableSample"/>.
/// </summary>
/// <param name="sampleInfo">The <see cref="ISampleInfo"/> to apply.</param>
/// <exception cref="InvalidOperationException">If an <see cref="ISampleInfo"/> has already been applied to this <see cref="PoolableSkinnableSample"/>.</exception>
public void Apply(ISampleInfo sampleInfo)
{
if (this.sampleInfo != null)
throw new InvalidOperationException($"A {nameof(PoolableSkinnableSample)} cannot be applied multiple {nameof(ISampleInfo)}s.");
this.sampleInfo = sampleInfo;
Volume.Value = sampleInfo.Volume / 100.0;
if (LoadState >= LoadState.Ready)
updateSample();
}
protected override void SkinChanged(ISkinSource skin)
{
base.SkinChanged(skin);
updateSample();
}
/// <summary>
/// Whether this sample was playing before a skin source change.
/// </summary>
View on GitHub (pinned to d9c73e12ad)
Solutions
- Return the sample to the pool (or dispose/recreate) before applying a new ISampleInfo.
- Ensure the pool resets sampleInfo to null on return; do not retain the instance across reuses.
- Use a fresh PoolableSkinnableSample per playback if pooling is unnecessary.
- Audit Apply call sites to confirm each is preceded by a pool Get (not a retained instance).
Example fix
// before sample.Apply(infoA); sample.Apply(infoB); // throws // after sample.Apply(infoA); pool.Return(sample); sample = pool.Get(); sample.Apply(infoB);
Defensive patterns
Strategy: validation
Validate before calling
if (sample.HasApplied)
throw new InvalidOperationException("Sample already applied; return to pool first."); Try / catch
try { sample.Apply(info); }
catch (InvalidOperationException) { sample = pool.Get(); sample.Apply(info); } Prevention
- Return PoolableSkinnableSample to the pool before re-Apply.
- Ensure pool reset clears sampleInfo.
- Use one sample instance per playback.
When it happens
Trigger: Calling Apply(sampleInfo) twice on the same PoolableSkinnableSample instance without returning it to the pool (or before it was reset) — the second Apply hits the guard.
Common situations: Pooling bug where a sample is not properly returned/reset before reuse; calling Apply in a loop without pooling discipline; holding a reference to a pooled sample and reusing it across plays.
Related errors
- Attempting to use this setter will not work correctly. Use s
- Setting {nameof(CurrentSkin)}'s value directly is not suppor
- Attempting to add a new component to a target container whic
- Attempting to remove a new component from a target container
- Invalid component type: {component}
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/8c592780e7bdb03f.
Report an issue: GitHub.