dotnet/aspnetcore · critical · ArgumentException

Invalid layout type: {layoutType.FullName} does not implemen

Error message

Invalid layout type: {layoutType.FullName} does not implement {typeof(IComponent).FullName}.

What it means

Thrown by the LayoutAttribute constructor when the type passed as the layout does not implement IComponent. Blazor requires every layout to be a renderable component, so the attribute validates this contract at construction time. The check uses typeof(IComponent).IsAssignableFrom(layoutType), so any non-component type (e.g. a plain class or interface) triggers it.

Source

Thrown at src/Components/Components/src/LayoutAttribute.cs:25

namespace Microsoft.AspNetCore.Components;

/// <summary>
/// Indicates that the associated component type uses a specified layout.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class LayoutAttribute : Attribute
{
    /// <summary>
    /// Constructs an instance of <see cref="LayoutAttribute"/>.
    /// </summary>
    /// <param name="layoutType">The type of the layout.</param>
    public LayoutAttribute([DynamicallyAccessedMembers(Component)] Type layoutType)
    {
        LayoutType = layoutType ?? throw new ArgumentNullException(nameof(layoutType));

        if (!typeof(IComponent).IsAssignableFrom(layoutType))
        {
            throw new ArgumentException($"Invalid layout type: {layoutType.FullName} " +
                $"does not implement {typeof(IComponent).FullName}.");
        }

        // Note that we can't validate its acceptance of a 'Body' parameter at this stage,
        // because the contract doesn't force them to be known statically. However it will
        // be a runtime error if the referenced component type rejects the 'Body' parameter
        // when it gets used.
    }

    /// <summary>
    /// The type of the layout. The type must implement <see cref="IComponent"/>
    /// and must accept a parameter with the name 'Body'.
    /// </summary>
    [DynamicallyAccessedMembers(Component)]
    public Type LayoutType { get; private set; }
}

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Make the referenced layout type implement IComponent, typically by inheriting from LayoutComponentBase or ComponentBase.
  2. Verify the type passed to [Layout(...)] is the component you intend (check the using/namespace resolution).
  3. Add a [Body] RenderFragment parameter to the layout so it functions as a real layout.

Example fix

// before
[Layout(typeof(MainLayoutShell))] // MainLayoutShell : UserControl, not a component
public class MyPage : ComponentBase { }

// after
[Layout(typeof(MainLayout))]   // MainLayout : LayoutComponentBase
public class MyPage : ComponentBase { }
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidLayout(Type t) => t != null && typeof(IComponent).IsAssignableFrom(t);

// before decorating or resolving:
if (!IsValidLayout(candidateLayoutType)) throw new InvalidOperationException($"{candidateLayoutType} is not a valid layout component.");

Type guard

static bool IsLayoutComponent(Type t) => typeof(IComponent).IsAssignableFrom(t);

Try / catch

try { var attr = new LayoutAttribute(layoutType); }
catch (ArgumentException ex) when (ex.Message.Contains("does not implement"))
{
    logger.LogError(ex, "Layout type invalid");
    throw;
}

Prevention

When it happens

Trigger: Decorating a class with [Layout(typeof(SomeNonComponentType))] where SomeNonComponentType does not implement IComponent; passing a Type instance to LayoutAttribute whose hierarchy does not include IComponent; referencing a layout type that was refactored away from inheriting ComponentBase/IComponent.

Common situations: Creating a custom layout that mistakenly inherits from a non-component base class; copy-pasting a layout reference and forgetting to inherit ComponentBase; Razor @layout directive resolving to a helper/utility class rather than a component; trimming/AOT scenarios where the type metadata is incomplete.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/8bf7b2395098dbe6. Report an issue: GitHub.