ppy/osu · error
Only scores in the osu, taiko, catch, or mania rulesets can
Error message
Only scores in the osu, taiko, catch, or mania rulesets can be encoded to the legacy score format.
What it means
Thrown by the LegacyScoreEncoder constructor when score.ScoreInfo.Ruleset.IsLegacyRuleset() is false. The legacy score format only supports the four original osu! rulesets; encoding for any other (e.g. lazer-only or custom) ruleset is rejected at construction time.
Source
Thrown at osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs:94
private readonly Score score;
private readonly IBeatmap? beatmap;
/// <summary>
/// Create a new score encoder for a specific score.
/// </summary>
/// <param name="score">The score to be encoded.</param>
/// <param name="beatmap">The beatmap used to convert frames for the score. May be null if the frames are already <see cref="LegacyReplayFrame"/>s.</param>
/// <exception cref="ArgumentException"></exception>
public LegacyScoreEncoder(Score score, IBeatmap? beatmap)
{
this.score = score;
this.beatmap = beatmap;
if (beatmap == null && !score.Replay.Frames.All(f => f is LegacyReplayFrame))
throw new ArgumentException(@"Beatmap must be provided if frames are not already legacy frames.", nameof(beatmap));
if (!score.ScoreInfo.Ruleset.IsLegacyRuleset())
throw new ArgumentException(@"Only scores in the osu, taiko, catch, or mania rulesets can be encoded to the legacy score format.", nameof(score));
}
public void Encode(Stream stream, bool leaveOpen = false)
{
using (SerializationWriter sw = new SerializationWriter(stream, leaveOpen))
{
sw.Write((byte)(score.ScoreInfo.Ruleset.OnlineID));
sw.Write(score.ScoreInfo.TotalScoreVersion);
sw.Write(score.ScoreInfo.BeatmapInfo!.MD5Hash);
sw.Write(score.ScoreInfo.User.Username);
sw.Write(FormattableString.Invariant($"lazer-{score.ScoreInfo.User.Username}-{score.ScoreInfo.Date}").ComputeMD5Hash());
sw.Write((ushort)(score.ScoreInfo.GetCount300() ?? 0));
sw.Write((ushort)(score.ScoreInfo.GetCount100() ?? 0));
sw.Write((ushort)(score.ScoreInfo.GetCount50() ?? 0));
sw.Write((ushort)(score.ScoreInfo.GetCountGeki() ?? 0));
sw.Write((ushort)(score.ScoreInfo.GetCountKatu() ?? 0));
sw.Write((ushort)(score.ScoreInfo.GetCountMiss() ?? 0));
sw.Write((int)(score.ScoreInfo.TotalScore));
View on GitHub (pinned to d9c73e12ad)
Solutions
- Filter to score.ScoreInfo.Ruleset.IsLegacyRuleset() before instantiating LegacyScoreEncoder.
- Use the lazer JSON score format (.osr-lazer) for non-legacy rulesets instead of the legacy encoder.
- Check OnlineID of the ruleset (0,1,2,3) as a quick pre-guard before constructing the encoder.
- Wrap construction in try/catch ArgumentException and skip non-encodable scores in batch exports.
Example fix
// before
var encoder = new LegacyScoreEncoder(score, beatmap);
// after
if (!score.ScoreInfo.Ruleset.IsLegacyRuleset())
throw new NotSupportedException($"Ruleset {score.ScoreInfo.Ruleset.ShortName} cannot be legacy-encoded.");
var encoder = new LegacyScoreEncoder(score, beatmap); Defensive patterns
Strategy: validation
Validate before calling
if (!score.ScoreInfo.Ruleset.IsLegacyRuleset())
throw new NotSupportedException("Use lazer score format for non-legacy rulesets."); Type guard
static bool IsLegacyEncodable(Score s) => s.ScoreInfo.Ruleset.IsLegacyRuleset();
Try / catch
try { new LegacyScoreEncoder(score, beatmap); }
catch (ArgumentException) { /* fall back to JSON encoder */ } Prevention
- Filter scores by IsLegacyRuleset() before legacy export.
- Reserve LegacyScoreEncoder for osu/taiko/catch/mania.
- Use the lazer JSON format for custom/lazer-only rulesets.
When it happens
Trigger: Constructing new LegacyScoreEncoder(score, beatmap) where score.ScoreInfo.Ruleset is not osu/taiko/catch/mania. The encoder cannot represent non-legacy rulesets in the stable binary format.
Common situations: Exporting a score from a custom ruleset; exporting a lazer-only gamemode; forgetting to filter scores by IsLegacyRuleset() before export.
Related errors
- Ruleset with ID of {RulesetID} not found locally
- Couldn't create score with unknown ruleset: {RulesetId}
- Ruleset with ID of {Score.RulesetID} not found locally
- Ruleset is not available locally.
- Only beatmaps in the osu, taiko, catch, or mania rulesets ca
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/4ec32361d9612c82.
Report an issue: GitHub.