dotnet/aspnetcore · error · InvalidOperationException

Attributes may only be added immediately after frames of…

Error message

Attributes may only be added immediately after frames of type {RenderTreeFrameType.Element} or {RenderTreeFrameType.Component}

What it means

AssertCanAddAttribute threw because the most recent non-attribute frame was neither Element nor Component. Attributes/component parameters can only follow an element or component opening; adding them after content, region, ref capture, etc. is invalid.

Solutions

  1. Reorder so AddAttribute/AddComponentParameter immediately follows OpenElement/OpenComponent (or other attributes).
  2. In custom code, track the last non-attribute frame type and re-open a scope before adding attributes if needed.
  3. Use higher-level Razor/ComponentBase authoring instead of raw RenderTreeBuilder where possible.

Example fix

// before
builder.OpenElement(0, "input");
builder.AddContent(1, "text");
builder.AddAttribute(2, "value", x); // last non-attr frame is now content

// after
builder.OpenElement(0, "input");
builder.AddAttribute(1, "value", x);
builder.AddContent(2, "text");
Defensive patterns

Strategy: validation

Validate before calling

if (lastNonAttributeFrameType != RenderTreeFrameType.Element &&
    lastNonAttributeFrameType != RenderTreeFrameType.Component)
    throw new InvalidOperationException("Open an element/component before adding attributes.");
builder.AddAttribute(seq, name, value);

Type guard

static bool CanAddAttributeAfter(RenderTreeFrameType last)
    => last == RenderTreeFrameType.Element || last == RenderTreeFrameType.Component;

Prevention

When it happens

Trigger: Calling AddAttribute/AddComponentParameter after AddContent, after CloseElement, after a reference capture, or at the root. Any sequence where _lastNonAttributeFrameType drifted away from Element/Component before an attribute append.

Common situations: Misordered manual tree construction. Source generators emitting attributes in the wrong slot. Custom component bases that emit parameters conditionally and miss the ordering invariant.

Related errors


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

Appendix: source

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

        _lastNonAttributeFrameType = RenderTreeFrameType.Region;
    }

    /// <summary>
    /// Marks a previously appended region frame as closed. Calls to this method
    /// must be balanced with calls to <see cref="OpenRegion(int)"/>.
    /// </summary>
    public void CloseRegion()
    {
        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

View on GitHub (pinned to 3600ca084e)