dotnet/aspnetcore · error · InvalidOperationException

Valueless attributes may only be added immediately after…

Error message

Valueless attributes may only be added immediately after frames of type {RenderTreeFrameType.Element}

What it means

AddAttribute(int, string) (the valueless/bool-true overload) was called when the last non-attribute frame on the builder was not an Element. Valueless attributes like `@bind`-less boolean HTML attributes are only meaningful on elements, so the builder rejects attaching one to a component or at the root.

Solutions

  1. Ensure OpenElement(...) was the most recent non-attribute frame before calling AddAttribute(seq, name).
  2. If the attribute is for a component parameter, use AddComponentParameter or the typed AddAttribute overloads instead.
  3. Reorder builder calls so the valueless attribute follows the element opening.

Example fix

// before
builder.AddAttribute(0, "readonly"); // no element open
builder.OpenElement(1, "input");

// after
builder.OpenElement(0, "input");
builder.AddAttribute(1, "readonly");
Defensive patterns

Strategy: validation

Validate before calling

// In custom builders, guard before valueless attribute
if (lastNonAttributeFrameType != RenderTreeFrameType.Element)
    throw new InvalidOperationException("Open an element first.");
builder.AddAttribute(seq, name);

Type guard

static bool CanAddValuelessAttribute(RenderTreeFrameType last) => last == RenderTreeFrameType.Element;

Prevention

When it happens

Trigger: Calling builder.AddAttribute(seq, "disabled") before any OpenElement, or right after OpenComponent. Razor compiling an attribute on a component using a valueless Razor directive attribute syntax.

Common situations: Authoring custom component bases / manual RenderTreeBuilder code. Razor syntax that emits a valueless attribute against a component tag. Misordering builder calls.

Related errors


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

Appendix: source

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

    /// <param name="textContent">Content for the new text frame.</param>
    public void AddContent(int sequence, object? textContent)
        => AddContent(sequence, textContent?.ToString());

    /// <summary>
    /// <para>
    /// Appends a frame representing a bool-valued attribute with value 'true'.
    /// </para>
    /// <para>
    /// The attribute is associated with the most recently added element.
    /// </para>
    /// </summary>
    /// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
    /// <param name="name">The name of the attribute.</param>
    public void AddAttribute(int sequence, string name)
    {
        if (_lastNonAttributeFrameType != RenderTreeFrameType.Element)
        {
            throw new InvalidOperationException($"Valueless attributes may only be added immediately after frames of type {RenderTreeFrameType.Element}");
        }

        _entries.AppendAttribute(sequence, name, ElementBoolTrueValue);
    }

    /// <summary>
    /// <para>
    /// Appends a frame representing a bool-valued attribute.
    /// </para>
    /// <para>
    /// The attribute is associated with the most recently added element. If the value is <c>false</c> and the
    /// current element is not a component, the frame will be omitted.
    /// </para>
    /// </summary>
    /// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
    /// <param name="name">The name of the attribute.</param>
    /// <param name="value">The value of the attribute.</param>
    public void AddAttribute(int sequence, string name, bool value)

View on GitHub (pinned to 3600ca084e)