dotnet/aspnetcore · error · InvalidOperationException

Incorrect frame type

Error message

Incorrect frame type: '{prevFrame.FrameTypeField}'

What it means

SetUpdatesAttributeName was called when the most recent frame is not an Attribute frame. The method must tag a preceding Attribute frame; any other frame type (Element, Component, Region, etc.) is rejected as 'Incorrect frame type'.

Solutions

  1. Reorder so the immediately preceding frame is the Attribute being tagged.
  2. Before calling, check _entries last frame type (in custom code: track the last frame type yourself).
  3. Use the higher-level AddAttribute overloads which preserve correct ordering automatically.

Example fix

// before
builder.AddAttribute(0, "onclick", handler);
builder.AddContent(1, "Click");
builder.SetUpdatesAttributeName("value"); // last frame is now content

// after
builder.AddAttribute(0, "onclick", handler);
builder.SetUpdatesAttributeName("value");
builder.AddContent(1, "Click");
Defensive patterns

Strategy: validation

Validate before calling

// Guard before calling
if (lastFrameType != RenderTreeFrameType.Attribute)
    throw new InvalidOperationException("Last frame must be Attribute.");
builder.SetUpdatesAttributeName(name);

Type guard

static bool LastFrameIsAttribute(RenderTreeFrameType t) => t == RenderTreeFrameType.Attribute;

Prevention

When it happens

Trigger: Calling SetUpdatesAttributeName after OpenElement, AddContent, CloseElement, or any non-attribute Append. Pipeline/ordering bugs in custom RenderTreeBuilder code or generated emitters.

Common situations: Tree builders that interleave content frames between the handler attribute and the SetUpdatesAttributeName call. Buggy source generators / Razor compilation. Test fakes that don't track frame order.

Related errors


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

Appendix: source

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

    /// </para>
    /// <para>
    /// This information is used by the rendering system to determine whether
    /// to accept a value update for the other attribute when receiving a
    /// call to the event handler.
    /// </para>
    /// </summary>
    /// <param name="updatesAttributeName">The name of another attribute whose value can be updated when the event handler is executed.</param>
    public void SetUpdatesAttributeName(string updatesAttributeName)
    {
        if (_entries.Count == 0)
        {
            throw new InvalidOperationException("No preceding attribute frame exists.");
        }

        ref var prevFrame = ref _entries.Buffer[_entries.Count - 1];
        if (prevFrame.FrameTypeField != RenderTreeFrameType.Attribute)
        {
            throw new InvalidOperationException($"Incorrect frame type: '{prevFrame.FrameTypeField}'");
        }

        prevFrame.AttributeEventUpdatesAttributeNameField = updatesAttributeName;
    }

    /// <summary>
    /// Appends a frame representing a child component.
    /// </summary>
    /// <typeparam name="TComponent">The type of the child component.</typeparam>
    /// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
    public void OpenComponent<[DynamicallyAccessedMembers(Component)] TComponent>(int sequence) where TComponent : notnull, IComponent
        => OpenComponentUnchecked(sequence, typeof(TComponent));

    /// <summary>
    /// Appends a frame representing a child component.
    /// </summary>
    /// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
    /// <param name="componentType">The type of the child component.</param>

View on GitHub (pinned to 3600ca084e)