ppy/osu · error · ArgumentException

Only beatmaps in the osu, taiko, catch, or mania rulesets ca

Error message

Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.

What it means

Thrown by the LegacyBeatmapEncoder constructor when the beatmap's ruleset OnlineID is outside the range 0–3. Only the four legacy rulesets (osu=0, taiko=1, catch=2, mania=3) can be encoded to the .osu legacy format. Custom rulesets have OnlineID values outside this range (often negative) and their mechanics cannot be represented in the legacy format.

Source

Thrown at osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs:53

        /// </summary>
        /// <param name="beatmap">The beatmap to encode.</param>
        /// <param name="skin">The beatmap's skin, used for encoding combo colours.</param>
        /// <param name="storyboard">
        /// The combined storyboard, loaded from both the <c>.osu</c> and the <c>.osz</c>.
        /// Only elements from the <c>.osu</c> (marked via <see cref="StoryboardElementSource.Beatmap"/>) will be encoded to the beatmap.
        /// </param>
        public LegacyBeatmapEncoder(IBeatmap beatmap, ISkin? skin, Storyboard? storyboard)
        {
            this.beatmap = beatmap;
            this.skin = skin;

            if (storyboard != null)
                storyboardEncoder = new LegacyStoryboardEncoder(storyboard);

            onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID;

            if (onlineRulesetID < 0 || onlineRulesetID > 3)
                throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
        }

        public void Encode(TextWriter writer)
        {
            writer.WriteLine($"osu file format v{FIRST_LAZER_VERSION}");

            writer.WriteLine();
            handleGeneral(writer);

            writer.WriteLine();
            handleEditor(writer);

            writer.WriteLine();
            handleMetadata(writer);

            writer.WriteLine();
            handleDifficulty(writer);

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Only use LegacyBeatmapEncoder for beatmaps in the osu, taiko, catch, or mania rulesets (OnlineID 0–3).
  2. Before constructing the encoder, check beatmap.BeatmapInfo.Ruleset.OnlineID and skip/handle custom rulesets differently.
  3. For custom rulesets, use a non-legacy encoding path or skip export entirely.

Example fix

// before
var encoder = new LegacyBeatmapEncoder(beatmap, skin, storyboard); // throws for custom rulesets

// after
if (beatmap.BeatmapInfo.Ruleset.OnlineID < 0 || beatmap.BeatmapInfo.Ruleset.OnlineID > 3)
    throw new NotSupportedException($"Ruleset {beatmap.BeatmapInfo.Ruleset.Name} cannot be encoded to legacy format");
var encoder = new LegacyBeatmapEncoder(beatmap, skin, storyboard);
Defensive patterns

Strategy: validation

Validate before calling

// Check ruleset OnlineID before encoding
int rulesetId = beatmap.BeatmapInfo.Ruleset.OnlineID;
if (rulesetId < 0 || rulesetId > 3)
    throw new NotSupportedException($"Ruleset {rulesetId} cannot be encoded to legacy .osu format");
var encoder = new LegacyBeatmapEncoder(beatmap, skin, storyboard);

Type guard

static bool CanEncodeToLegacy(IBeatmap beatmap)
{
    int id = beatmap.BeatmapInfo.Ruleset.OnlineID;
    return id >= 0 && id <= 3;
}

Prevention

When it happens

Trigger: Constructing `new LegacyBeatmapEncoder(beatmap, skin, storyboard)` where beatmap.BeatmapInfo.Ruleset.OnlineID is <0 or >3 — i.e. a custom/experimental ruleset beatmap (e.g. senton, rush, tau, etc.).

Common situations: Attempting to export/save a custom ruleset beatmap in legacy .osu format; programmatically creating a LegacyBeatmapEncoder for a beatmap whose ruleset isn't one of the four standard ones; a ruleset that reports OnlineID=-1 (unregistered) being passed to the encoder.

Related errors


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