ppy/osu · error
The score specifies an incompatible set of mods!
Error message
The score specifies an incompatible set of mods!
What it means
Thrown during ScoreImporter.PreImport when ModUtils.CheckCompatibleSet(model.Mods) returns false, i.e. the score's mod list contains mutually incompatible mods (e.g. conflicting difficulty reducers, duplicates, or multipliers that cancel). The importer refuses to persist a score with an impossible mod combination.
Source
Thrown at osu.Game/Scoring/ScoreImporter.cs:95
protected override void Populate(ScoreInfo model, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default)
{
Debug.Assert(model.BeatmapInfo != null);
// Ensure the beatmap is not detached.
if (!model.BeatmapInfo.IsManaged)
model.BeatmapInfo = realm.Find<BeatmapInfo>(model.BeatmapInfo.ID)!;
if (!model.Ruleset.IsManaged)
model.Ruleset = realm.Find<RulesetInfo>(model.Ruleset.ShortName)!;
// These properties are known to be non-null, but these final checks ensure a null hasn't come from somewhere (or the refetch has failed).
// Under no circumstance do we want these to be written to realm as null.
ArgumentNullException.ThrowIfNull(model.BeatmapInfo);
ArgumentNullException.ThrowIfNull(model.Ruleset);
if (!ModUtils.CheckCompatibleSet(model.Mods))
throw new InvalidOperationException(@"The score specifies an incompatible set of mods!");
if (string.IsNullOrEmpty(model.StatisticsJson))
model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics);
if (string.IsNullOrEmpty(model.MaximumStatisticsJson))
model.MaximumStatisticsJson = JsonConvert.SerializeObject(model.MaximumStatistics);
}
// Very naive local caching to improve performance of large score imports (where the username is usually the same for most or all scores).
// TODO: `UserLookupCache` cannot currently be used here because of async foibles.
// It only supports lookups by user ID (username would require web changes), and even then the ID lookups cannot be used.
// That is because that component provides an async interface, and async functions cannot be consumed safely here due to the rigid structure of `RealmArchiveModelImporter`.
// The importer has two paths, one async and one sync; the async path runs the sync path in a task.
// This means that sometimes `PostImport()` is called from a sync context, and sometimes from an async one, whilst itself being a sync method.
// That in turn makes `.GetResultSafely()` not callable inside `PostImport()`, as it will throw when called from an async context,
private readonly Dictionary<int, APIUser> idLookupCache = new Dictionary<int, APIUser>();
private readonly Dictionary<string, APIUser> usernameLookupCache = new Dictionary<string, APIUser>();
View on GitHub (pinned to d9c73e12ad)
Solutions
- Inspect model.Mods and run ModUtils.CheckCompatibleSet locally to identify the offending pair(s).
- Strip the incompatible mod(s) before import, or reject the score as invalid.
- If a legit score fails after a ruleset update, re-evaluate the mod's IncompatibleMods/Multiplier handling.
- For batch imports, log and quarantine incompatible scores rather than aborting the run.
Example fix
// before
if (!ModUtils.CheckCompatibleSet(model.Mods))
throw new InvalidOperationException(@"The score specifies an incompatible set of mods!");
// after (diagnostic)
if (!ModUtils.CheckCompatibleSet(model.Mods, out var invalidMods))
throw new InvalidOperationException($"Incompatible mods: {string.Join(", ", invalidMods.Select(m => m.Name))}"); Defensive patterns
Strategy: validation
Validate before calling
if (!ModUtils.CheckCompatibleSet(score.Mods))
throw new InvalidOperationException("Refusing to import score with incompatible mods."); Type guard
static bool HasCompatibleMods(ScoreInfo s) => ModUtils.CheckCompatibleSet(s.Mods);
Try / catch
try { importer.Import(score); }
catch (InvalidOperationException ex) when (ex.Message.Contains("incompatible set of mods")) { /* quarantine */ } Prevention
- Run ModUtils.CheckCompatibleSet before import.
- Sanitize mod lists from untrusted replay sources.
- After ruleset mod changes, re-validate stored scores before re-import.
When it happens
Trigger: Importing a score whose Mods array fails ModUtils.CheckCompatibleSet: duplicate mods, mods that blacklist each other (e.g. two multipliers), or a mod marked incompatible with another present mod.
Common situations: Tampered or hand-crafted .osr/.json scores with illegal mod combos; a mod's IncompatibleMods list was broadened and old scores now fail re-import; ruleset mod changes that made previously-allowed combos invalid.
Related errors
- {Path} is not a valid archive
- Provided client ID must be an integer.
- Can't have zero or fewer stages.
- No valid beatmap files found in the beatmap archive.
- {setInfo.GetDisplayString()} already has a difficulty with t
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/c6282ee158aaad27.
Report an issue: GitHub.