ppy/osu · warning · InvalidOperationException

Attempting to use this setter will not work correctly. Use s

Error message

Attempting to use this setter will not work correctly. Use specific init-only properties exposed by {nameof(LegacySpriteText)} instead.

What it means

Thrown by the Font setter on LegacySpriteText, which is intentionally shadowed (new) to hard-block callers from using the inherited SpriteText.Font property. LegacySpriteText derives its font entirely from the LegacyFont passed to its constructor plus its init-only properties, so the inherited setter would silently do nothing useful.

Source

Thrown at osu.Game/Skinning/LegacySpriteText.cs:38

        public const char PP_SUFFIX_CHAR = '\uebd9';

        public Vector2? MaxSizePerGlyph { get; init; }
        public bool FixedWidth { get; init; }

        private readonly LegacyFont font;

        private LegacyGlyphStore glyphStore = null!;

        protected override char FixedWidthReferenceCharacter => '5';

        protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x', PP_SUFFIX_CHAR };

        // ReSharper disable once UnusedMember.Global
        // being unused is the point here
        public new FontUsage Font
        {
            get => base.Font;
            set => throw new InvalidOperationException(@"Attempting to use this setter will not work correctly. "
                                                       + $@"Use specific init-only properties exposed by {nameof(LegacySpriteText)} instead.");
        }

        public LegacySpriteText(LegacyFont font)
        {
            this.font = font;

            Shadow = false;
            UseFullGlyphHeight = false;
        }

        [BackgroundDependencyLoader]
        private void load(ISkinSource skin)
        {
            string fontPrefix = skin.GetFontPrefix(font);
            base.Font = new FontUsage(fontPrefix, 1, fixedWidth: FixedWidth);
            Spacing = new Vector2(-skin.GetFontOverlap(font), 0);

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Do not set Font on LegacySpriteText; instead set its init-only properties (FontFace, Size, etc.) or construct it with the correct LegacyFont.
  2. Type-check before applying a generic Font: if (text is LegacySpriteText lst) { /* use init-only props */ } else { text.Font = font; }.
  3. Refactor generic font appliers to go through an abstraction that LegacySpriteText implements differently.

Example fix

// before
text.Font = new FontUsage("Arial", 20f);

// after (LegacySpriteText)
var lst = (LegacySpriteText)text;
// configure via constructor or init-only props, e.g.:
lst.Size = 20f; // or whatever init-only property applies
Defensive patterns

Strategy: type-guard

Validate before calling

if (text is LegacySpriteText)
    throw new InvalidOperationException("LegacySpriteText does not accept Font setter; use init-only props.");

Type guard

static bool IsLegacySpriteText(SpriteText t) => t is LegacySpriteText;

Try / catch

try { text.Font = font; }
catch (InvalidOperationException) { /* apply via legacy-specific path */ }

Prevention

When it happens

Trigger: Calling spriteText.Font = new FontUsage(...) on a LegacySpriteText instance, or via XAML/builder code that sets the inherited Font property generically.

Common situations: Generic code that sets Font on any SpriteText (e.g. a style applier) running against a LegacySpriteText; porting component code from SpriteText to LegacySpriteText without updating the font configuration.

Related errors


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