dotnet/aspnetcore · error · InvalidOperationException

The frame at index {frameIndex} is of type '{frame.FrameType

Error message

The frame at index {frameIndex} is of type '{frame.FrameTypeField}', not 'Attribute'.

What it means

Thrown by RenderTreeBuilder.SetAttributeValue (the experimental API for mutating an already-appended attribute frame in place). It checks the frame at frameIndex is of type Attribute; SetAttributeValue only updates attribute values, so pointing it at an element/component/text frame is rejected.

Source

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

    /// <param name="frameIndex">The zero-based index of the attribute frame whose value should be replaced.</param>
    /// <param name="value">The new attribute value.</param>
    /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="frameIndex"/> is outside the range of appended frames.</exception>
    /// <exception cref="InvalidOperationException">Thrown when the frame at <paramref name="frameIndex"/> is not of type <see cref="RenderTreeFrameType.Attribute"/>.</exception>
    [Experimental("ASP0032", UrlFormat = "https://aka.ms/aspnet/analyzer/{0}")]
    public void SetAttributeValue(int frameIndex, object? value)
    {
        var frames = _entries.Buffer;
        var count = _entries.Count;

        if ((uint)frameIndex >= (uint)count)
        {
            throw new ArgumentOutOfRangeException(nameof(frameIndex));
        }

        ref var frame = ref frames[frameIndex];
        if (frame.FrameTypeField != RenderTreeFrameType.Attribute)
        {
            throw new InvalidOperationException(
                $"The frame at index {frameIndex} is of type '{frame.FrameTypeField}', not '{RenderTreeFrameType.Attribute}'.");
        }

        frame.AttributeValueField = value;
    }

    internal void AssertTreeIsValid(IComponent component)
    {
        if (_openElementIndices.Count > 0)
        {
            // It's never valid to leave an element/component/region unclosed. Doing so
            // could cause undefined behavior in diffing.
            ref var invalidFrame = ref _entries.Buffer[_openElementIndices.Peek()];
            throw new InvalidOperationException($"Render output is invalid for component of type '{component.GetType().FullName}'. A frame of type '{invalidFrame.FrameType}' was left unclosed. Do not use try/catch inside rendering logic, because partial output cannot be undone.");
        }
    }

    // Internal for testing

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Recompute the target frame index from the current frames array before calling SetAttributeValue.
  2. Confirm the frame at that index is an Attribute frame (filter by RenderTreeFrameType.Attribute) before mutating.
  3. If frames may have shifted, re-scan by attribute name instead of trusting a cached index.

Example fix

// before
var idx = cachedIndex; // possibly stale
builder.SetAttributeValue(idx, "new");

// after
var frames = builder.GetFrames();
int idx = -1;
for (int i = 0; i < frames.Count; i++)
    if (frames.Array[i].FrameTypeField == RenderTreeFrameType.Attribute
        && frames.Array[i].AttributeNameField == "value") { idx = i; break; }
if (idx >= 0) builder.SetAttributeValue(idx, "new");
Defensive patterns

Strategy: validation

Validate before calling

// Resolve and type-check the frame index immediately before mutating.
var frames = builder.GetFrames();
if ((uint)frameIndex < (uint)frames.Count
    && frames.Array[frameIndex].FrameTypeField == RenderTreeFrameType.Attribute)
{
    builder.SetAttributeValue(frameIndex, value);
}

Type guard

static bool IsAttributeFrame(in RenderTreeFrame f)
    => f.FrameTypeField == RenderTreeFrameType.Attribute;

Prevention

When it happens

Trigger: Calling builder.SetAttributeValue(frameIndex, value) with an index that refers to a non-Attribute frame (element, component, text, region, etc.). Typically an off-by-one or a stale index captured before re-appending frames.

Common situations: Wrapping a RenderFragment and caching a frame index, then the index drifts after the fragment re-renders or after InsertAttributeExpensive shifts frames; miscounting sequence vs. physical frame index.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/61203deca54eb516. Report an issue: GitHub.