dotnet/aspnetcore · error · InvalidOperationException

No preceding attribute frame exists.

Error message

No preceding attribute frame exists.

What it means

SetUpdatesAttributeName was called when the builder has no frames yet (_entries.Count == 0). The method tags the most recently appended frame as one whose value should be refreshed when an event handler fires, so it requires a preceding Attribute frame to operate on.

Solutions

  1. Call AddAttribute(...) for the event-handler attribute before SetUpdatesAttributeName.
  2. Verify the builder has at least one frame and the previous frame is an Attribute before invoking.
  3. Restructure emission order so the update-target attribute precedes the SetUpdatesAttributeName call.

Example fix

// before
builder.SetUpdatesAttributeName("value");
builder.OpenElement(0, "input");

// after
builder.OpenElement(0, "input");
builder.AddAttribute(1, "oninput", handler);
builder.SetUpdatesAttributeName("value");
Defensive patterns

Strategy: validation

Validate before calling

// Guard in custom tree-build code
if (entries.Count == 0) throw new InvalidOperationException("Append an attribute first.");
builder.SetUpdatesAttributeName(name);

Prevention

When it happens

Trigger: Calling builder.SetUpdatesAttributeName(name) as the very first operation, or after Clear() with nothing re-appended. Misordered manual tree construction.

Common situations: Hand-written RenderTreeBuilder code that emits event-handler wiring. Custom Razor-emitted code generators that emit SetUpdatesAttributeName at the wrong point.

Related errors


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

Appendix: source

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

    }

    /// <summary>
    /// <para>
    /// Indicates that the preceding attribute represents an event handler
    /// whose execution updates the attribute with name <paramref name="updatesAttributeName"/>.
    /// </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));

View on GitHub (pinned to 3600ca084e)