dotnet/aspnetcore · error · InvalidOperationException

Component parameters may only be added immediately after…

Error message

Component parameters may only be added immediately after frames of type {RenderTreeFrameType.Component}

What it means

RenderTreeBuilder.AddComponentParameter (and the related AssertCanAddComponentParameter guard) requires that the immediately preceding non-attribute frame be a Component frame. Blazor builds its render tree as an ordered sequence of frames; component parameters are child metadata of a component frame and are only legal while a component is the open context. Adding a parameter when the last structural frame is an Element, Region, or nothing at all corrupts the tree, so the builder throws InvalidOperationException immediately.

Solutions

  1. Ensure every AddComponentParameter call is preceded by an unmatched OpenComponent<T> on the same builder, with no CloseComponent in between.
  2. Replace any AddComponentParameter intended for an element with AddAttribute (element attributes use AddAttribute; only component parameters use AddComponentParameter).
  3. Audit the RenderFragment for an uneven Open/Close sequence — every OpenComponent must pair with exactly one CloseComponent before the fragment returns.
  4. If generating trees dynamically, track open-frame depth yourself and assert it before emitting a parameter.

Example fix

// before
builder.OpenElement(0, "div");
builder.AddComponentParameter(1, "Foo", 42); // throws
// after
builder.OpenComponent<MyComponent>(0);
builder.AddComponentParameter(1, "Foo", 42);
builder.CloseComponent();
Defensive patterns

Strategy: validation

Validate before calling

// Before emitting a component parameter, ensure the builder is inside an open component.
// RenderTreeBuilder does not expose _lastNonAttributeFrameType publicly, so the
// discipline is structural: pair every AddComponentParameter with a preceding OpenComponent.
static bool IsInsideComponentBranch(Stack<RenderTreeFrameType> openFrames)
    => openFrames.Count > 0 && openFrames.Peek() == RenderTreeFrameType.Component;

Type guard

// Static guard for hand-written render fragments: track open-frame type yourself.
readonly struct RenderScope : IDisposable {
    public RenderTreeFrameType FrameType { get; }
    public RenderScope(RenderTreeFrameType t) => FrameType = t;
    public void Dispose() { }
}
static RenderScope ComponentScope<T>(RenderTreeBuilder b, int seq) {
    b.OpenComponent<T>(seq); return new(RenderTreeFrameType.Component);
}

Prevention

When it happens

Trigger: Calling builder.AddComponentParameter(...) before builder.OpenComponent(...), or after builder.CloseComponent(), or after builder.OpenElement(...) without opening a component. Also triggered by calling AddComponentParameter after OpenRegion or at the root of an empty builder, because _lastNonAttributeFrameType is not RenderTreeFrameType.Component.

Common situations: Hand-written RenderFragment delegates that build markup imperatively; copy-pasting element attribute code (AddAttribute) into a component path and forgetting to swap to AddComponentParameter ordering; refactoring a component fragment and leaving a stray AddComponentParameter call after a CloseComponent; runtime-emitted trees from dynamic component generation libraries.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/227064fb391ca45f. Report an issue: GitHub.

Appendix: source

Thrown at src/Components/Components/src/Rendering/RenderTreeBuilder.cs:732

    {
        var indexOfEntryBeingClosed = _openElementIndices.Pop();
        _entries.Buffer[indexOfEntryBeingClosed].RegionSubtreeLengthField = _entries.Count - indexOfEntryBeingClosed;
    }

    private void AssertCanAddAttribute()
    {
        if (_lastNonAttributeFrameType != RenderTreeFrameType.Element
            && _lastNonAttributeFrameType != RenderTreeFrameType.Component)
        {
            throw new InvalidOperationException($"Attributes may only be added immediately after frames of type {RenderTreeFrameType.Element} or {RenderTreeFrameType.Component}");
        }
    }

    private void AssertCanAddComponentParameter()
    {
        if (_lastNonAttributeFrameType != RenderTreeFrameType.Component)
        {
            throw new InvalidOperationException($"Component parameters may only be added immediately after frames of type {RenderTreeFrameType.Component}");
        }
    }

    private int? GetCurrentParentFrameIndex()
        => _openElementIndices.Count == 0 ? (int?)null : _openElementIndices.Peek();

    private RenderTreeFrameType? GetCurrentParentFrameType()
    {
        var parentIndex = GetCurrentParentFrameIndex();
        return parentIndex.HasValue
            ? _entries.Buffer[parentIndex.Value].FrameTypeField
            : (RenderTreeFrameType?)null;
    }

    /// <summary>
    /// Clears the builder.
    /// </summary>
    public void Clear()

View on GitHub (pinned to 3600ca084e)