ppy/osu · error · RulesetLoadException

Ruleset could not be loaded (Instantiation failure)

Error message

Ruleset could not be loaded (Instantiation failure)

What it means

Thrown by RulesetInfo.CreateInstance when Activator.CreateInstance(type) succeeds but the resulting object cannot be cast to Ruleset. This means the type referenced by InstantiationInfo exists in the loaded assemblies but does not inherit from osu.Game.Rulesets.Ruleset. It is distinct from the 'Type lookup failure' sibling (type == null) and 'Ruleset not available' (Available flag off).

Source

Thrown at osu.Game/Rulesets/RulesetInfo.cs:110

            InstantiationInfo = InstantiationInfo,
            Available = Available,
            LastAppliedDifficultyVersion = LastAppliedDifficultyVersion,
        };

        public Ruleset CreateInstance()
        {
            if (!Available)
                throw new RulesetLoadException(@"Ruleset not available");

            var type = Type.GetType(InstantiationInfo);

            if (type == null)
                throw new RulesetLoadException(@"Type lookup failure");

            var ruleset = Activator.CreateInstance(type) as Ruleset;

            if (ruleset == null)
                throw new RulesetLoadException(@"Instantiation failure");

            // overwrite the pre-populated RulesetInfo with a potentially database attached copy.
            // TODO: figure if we still want/need this after switching to realm.
            // ruleset.RulesetInfo = this;

            return ruleset;
        }
    }
}

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Inspect the value of InstantiationInfo for the offending ruleset and confirm the named type is a non-abstract Ruleset subclass in a loaded assembly.
  2. If the ruleset type was renamed/moved, update InstantiationInfo (or delete and re-register the RulesetInfo row) to point at the correct fully-qualified type name.
  3. If the ruleset assembly is missing or incompatible, remove/disable the ruleset entry rather than letting instantiation proceed.
  4. Wrap CreateInstance() calls in ruleset-loading UI with a RulesetLoadException handler to surface a user-facing message instead of crashing.

Example fix

// before
var type = Type.GetType(InstantiationInfo);
var ruleset = Activator.CreateInstance(type) as Ruleset;

// after (diagnostic)
var type = Type.GetInstance(InstantiationInfo);
if (type != null && !typeof(Ruleset).IsAssignableFrom(type))
    throw new RulesetLoadException($@"Type {type.FullName} is not a Ruleset subclass.");
var ruleset = Activator.CreateInstance(type) as Ruleset;
Defensive patterns

Strategy: validation

Validate before calling

var type = Type.GetType(instantiationInfo);
if (type == null || !typeof(Ruleset).IsAssignableFrom(type) || type.IsAbstract)
    return; // skip; do not call CreateInstance()
var ruleset = (Ruleset)Activator.CreateInstance(type);

Type guard

static bool IsInstantiableRuleset(string instantiationInfo)
    => Type.GetType(instantiationInfo) is Type t
       && typeof(Ruleset).IsAssignableFrom(t)
       && !t.IsAbstract;

Try / catch

try { return rulesetInfo.CreateInstance(); }
catch (RulesetLoadException ex) { Logger.Log($"Ruleset load failed: {ex.Message}"); return null; }

Prevention

When it happens

Trigger: InstantiationInfo points to a Type that is not a Ruleset subclass (e.g. a class named similarly, a RulesetInfo subclass, or a stub). Occurs when a ruleset assembly is present but the declared InstantiationInfo string names a non-Ruleset type.

Common situations: Migrating a custom ruleset that renamed its primary Ruleset class but left the database/InstantiationInfo pointing at the old name; corrupted RulesetInfo rows after an incompatible ruleset update; a ruleset DLL that only partially matches the expected API.

Related errors


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