ppy/osu · error · ArgumentException

Provided argument must be of type {nameof(Drawable)}.

Error message

Provided argument must be of type {nameof(Drawable)}.

What it means

Thrown by SkinnableContainer.Add when the ISerialisableDrawable passed in is not a Drawable. The container's backing content requires a Drawable to insert into the draw tree; pure interface implementations without Drawable are rejected.

Source

Thrown at osu.Game/Skinning/SkinnableContainer.cs:88

            LoadComponentAsync(content, wrapper =>
            {
                AddInternal(wrapper);
                components.AddRange(wrapper.Children.OfType<ISerialisableDrawable>());
                ComponentsLoaded = true;
                OnComponentsLoaded?.Invoke(this);
            }, (cancellationSource = new CancellationTokenSource()).Token);
        }

        /// <inheritdoc cref="ISerialisableDrawableContainer"/>
        /// <exception cref="NotSupportedException">Thrown when attempting to add an element to a target which is not supported by the current skin.</exception>
        /// <exception cref="ArgumentException">Thrown if the provided instance is not a <see cref="Drawable"/>.</exception>
        public void Add(ISerialisableDrawable component)
        {
            if (content == null)
                throw new NotSupportedException("Attempting to add a new component to a target container which is not supported by the current skin.");

            if (!(component is Drawable drawable))
                throw new ArgumentException($"Provided argument must be of type {nameof(Drawable)}.", nameof(component));

            content.Add(drawable);
            components.Add(component);
        }

        /// <inheritdoc cref="ISerialisableDrawableContainer"/>
        /// <exception cref="NotSupportedException">Thrown when attempting to add an element to a target which is not supported by the current skin.</exception>
        /// <exception cref="ArgumentException">Thrown if the provided instance is not a <see cref="Drawable"/>.</exception>
        public void Remove(ISerialisableDrawable component, bool disposeImmediately)
        {
            if (content == null)
                throw new NotSupportedException("Attempting to remove a new component from a target container which is not supported by the current skin.");

            if (!(component is Drawable drawable))
                throw new ArgumentException($"Provided argument must be of type {nameof(Drawable)}.", nameof(component));

            content.Remove(drawable, disposeImmediately);
            components.Remove(component);

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Ensure the component class inherits from Drawable (and implements ISerialisableDrawable).
  2. Pass the underlying Drawable instance rather than a non-drawable wrapper.
  3. Type-check before Add: if (component is Drawable) container.Add(component); else log error.

Example fix

// before
class MyComponent : ISerialisableDrawable { ... } // not a Drawable
container.Add(new MyComponent());

// after
class MyComponent : Drawable, ISerialisableDrawable { ... }
container.Add(new MyComponent());
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(component is Drawable))
    throw new ArgumentException("Component must be a Drawable.");

Type guard

static bool IsDrawableComponent(ISerialisableDrawable c) => c is Drawable;

Try / catch

try { container.Add(component); }
catch (ArgumentException) { /* not a Drawable */ }

Prevention

When it happens

Trigger: Passing an ISerialisableDrawable implementation that does not derive from Drawable (the framework's Drawable base class) to Add().

Common situations: Custom serialisable component implemented as a plain class implementing the interface but not extending Drawable; passing a wrapper/DTO instead of the real component.

Related errors


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