ppy/osu · error

Legacy replay cannot be converted for the ruleset: {currentR

Error message

Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}

What it means

Thrown in convertFrame when currentRuleset.CreateConvertibleReplayFrame() returns null, meaning the active ruleset does not implement legacy-to-modern replay frame conversion. The decoder was asked to translate legacy replay frames into the ruleset's native frame type but the ruleset offers no converter.

Source

Thrown at osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs:358

            foreach (var legacyFrame in legacyFrames)
            {
                // never allow backwards time traversal in relation to the current frame.
                // this handles frames with negative delta.
                // this doesn't match stable 100% as stable will do something similar to adding an interpolated "intermediate frame"
                // at the point wherein time flow changes from backwards to forwards, but it'll do for now.
                if (currentFrame != null && legacyFrame.Time < currentFrame.Time)
                    continue;

                replay.Frames.Add(currentFrame = convertFrame(legacyFrame, currentFrame));
            }
        }

        private ReplayFrame convertFrame(LegacyReplayFrame currentFrame, ReplayFrame lastFrame)
        {
            var convertible = currentRuleset.CreateConvertibleReplayFrame();
            if (convertible == null)
                throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}");

            convertible.FromLegacy(currentFrame, currentBeatmap, lastFrame);

            var frame = (ReplayFrame)convertible;
            frame.Time = currentFrame.Time;

            return frame;
        }

        /// <summary>
        /// Retrieves the <see cref="Ruleset"/> for a specific id.
        /// </summary>
        /// <param name="rulesetId">The id.</param>
        /// <returns>The <see cref="Ruleset"/>.</returns>
        protected abstract Ruleset GetRuleset(int rulesetId);

        /// <summary>
        /// Retrieves the <see cref="WorkingBeatmap"/> corresponding to an MD5 hash.

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Confirm the ruleset is one of the legacy-capable rulesets (osu, taiko, catch, mania) before attempting legacy replay conversion.
  2. If authoring a custom ruleset, implement CreateConvertibleReplayFrame() to return a type deriving from ConvertibleReplayFrame.
  3. Guard the decode path: skip conversion (or report 'unsupported') when currentRuleset.CreateConvertibleReplayFrame() == null instead of forcing it.
  4. Check that the score's RulesetID matches the ruleset the replay was recorded under.

Example fix

// before
var convertible = currentRuleset.CreateConvertibleReplayFrame();
if (convertible == null)
    throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}");

// after (caller-side guard)
if (currentRuleset.CreateConvertibleReplayFrame() == null)
{
    Logger.Log($"Ruleset '{currentRuleset.Description}' does not support legacy replay conversion; skipping.");
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

if (currentRuleset.CreateConvertibleReplayFrame() == null)
{
    Logger.Log($"No legacy converter for {currentRuleset.Description}; skipping conversion.");
    return;
}

Type guard

static bool RulesetSupportsLegacyConversion(Ruleset r)
    => r.CreateConvertibleReplayFrame() != null;

Try / catch

try { convertFrame(legacyFrame, lastFrame); }
catch (InvalidOperationException) { /* ruleset cannot convert legacy replay */ }

Prevention

When it happens

Trigger: A legacy replay (osu!stable format) is being decoded/converted for a ruleset whose CreateConvertibleReplayFrame() returns null. Common with non-legacy or custom rulesets that never defined a LegacyReplayFrame converter.

Common situations: Importing a stable replay for a ruleset that does not support legacy replays; switching a score's target ruleset at runtime to one without a converter; using a custom ruleset that forgot to override CreateConvertibleReplayFrame.

Related errors


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