dotnet/aspnetcore · error · InvalidOperationException

The frame at index is of type ' ', not ' '.

Error message

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

What it means

RenderTreeBuilder's internal frame mutation API (the one that updates an attribute value by index) validates that the targeted frame is actually an Attribute frame. The render buffer is a heterogeneous array where element frames, component frames, attribute frames, and text frames are interleaved; writing an attribute value slot into a frame that holds, say, an Element or Text would silently corrupt the tree. The guard throws InvalidOperationException naming the mismatched frame type so the corruption is caught at the source.

Solutions

  1. Do not index into the builder's frames directly — re-derive the attribute frame index by scanning only Attribute frames after the owning element/component open.
  2. If you must mutate, use RenderTreeFrame.ElementAtOrDefault / frame iteration helpers that check FrameTypeField == Attribute before writing.
  3. Upgrade any code caching frame indices across renders to recompute them every render.
  4. Prefer the public AddAttribute/AddComponentParameter path over internal SetAttributeValue unless you are the renderer.

Example fix

// before (unsafe index reuse)
var idx = cachedAttributeIndex;
builder.SetAttributeValue(idx, newValue); // throws if idx now points at a non-attribute frame
// after
// re-scan for the attribute frame owned by the current element
ref var frame = ref FindAttributeFrame(builder, elementOpenIndex);
if (frame.FrameTypeField == RenderTreeFrameType.Attribute) {
    frame.AttributeValueField = newValue;
}
Defensive patterns

Strategy: validation

Validate before calling

// When indexing into the render buffer to mutate an attribute, validate the frame first.
ref var frame = ref frames[frameIndex];
if (frame.FrameTypeField != RenderTreeFrameType.Attribute)
    throw new InvalidOperationException($"Refusing to write: frame {frameIndex} is {frame.FrameTypeField}");
frame.AttributeValueField = value;

Type guard

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

Prevention

When it happens

Trigger: Calling the internal SetAttributeValue(int frameIndex, ...) overload (or the diff/edits APIs that index into _entries.Buffer) with an index that resolves to a non-Attribute frame. Typically arises in custom renderers, tree-diffing code, or reflection-based tree rewriting that computed the index from the wrong frame scan.

Common situations: Writing a custom RenderTreeBuilder manipulation outside the supported public API; upgrading across Blazor versions where frame layout changed and stale frame indices are cached; Hot-reload or component-diff tooling that holds indices across renders; tests that poke the builder's internal buffer directly.

Related errors


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

Appendix: 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 3600ca084e)