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 testingView on GitHub (pinned to 294cab2f9b)
Solutions
- Recompute the target frame index from the current frames array before calling SetAttributeValue.
- Confirm the frame at that index is an Attribute frame (filter by RenderTreeFrameType.Attribute) before mutating.
- 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
- Treat SetAttributeValue as experimental (ASP0032) and prefer full re-render over in-place mutation.
- Never cache a frame index across renders — re-derive it from the current frames each time.
- Scope-mutation: scan by attribute name rather than trusting a stale index.
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
- Element reference captures may only be added as children of
- Component reference captures may only be added as children o
- There is no enclosing component frame.
- The enclosing frame is not of the required type 'Component'.
- Named events may only be added as children of frames of type
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/61203deca54eb516.
Report an issue: GitHub.