{"record":{"id":"e0e69d8702d76d10","repo":"dotnet/aspnetcore","slug":"attributes-may-only-be-added-immediately-after-fra","errorCode":null,"errorMessage":"Attributes may only be added immediately after frames of type {RenderTreeFrameType.Element} or {RenderTreeFrameType.Component}","messagePattern":"Attributes may only be added immediately after frames of type (.+?) or (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/Rendering/RenderTreeBuilder.cs","lineNumber":724,"sourceCode":"        _lastNonAttributeFrameType = RenderTreeFrameType.Region;\n    }\n\n    /// <summary>\n    /// Marks a previously appended region frame as closed. Calls to this method\n    /// must be balanced with calls to <see cref=\"OpenRegion(int)\"/>.\n    /// </summary>\n    public void CloseRegion()\n    {\n        var indexOfEntryBeingClosed = _openElementIndices.Pop();\n        _entries.Buffer[indexOfEntryBeingClosed].RegionSubtreeLengthField = _entries.Count - indexOfEntryBeingClosed;\n    }\n\n    private void AssertCanAddAttribute()\n    {\n        if (_lastNonAttributeFrameType != RenderTreeFrameType.Element\n            && _lastNonAttributeFrameType != RenderTreeFrameType.Component)\n        {\n            throw new InvalidOperationException($\"Attributes may only be added immediately after frames of type {RenderTreeFrameType.Element} or {RenderTreeFrameType.Component}\");\n        }\n    }\n\n    private void AssertCanAddComponentParameter()\n    {\n        if (_lastNonAttributeFrameType != RenderTreeFrameType.Component)\n        {\n            throw new InvalidOperationException($\"Component parameters may only be added immediately after frames of type {RenderTreeFrameType.Component}\");\n        }\n    }\n\n    private int? GetCurrentParentFrameIndex()\n        => _openElementIndices.Count == 0 ? (int?)null : _openElementIndices.Peek();\n\n    private RenderTreeFrameType? GetCurrentParentFrameType()\n    {\n        var parentIndex = GetCurrentParentFrameIndex();\n        return parentIndex.HasValue","sourceCodeStart":706,"sourceCodeEnd":742,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Components/src/Rendering/RenderTreeBuilder.cs#L706-L742","documentation":"AssertCanAddAttribute threw because the most recent non-attribute frame was neither Element nor Component. Attributes/component parameters can only follow an element or component opening; adding them after content, region, ref capture, etc. is invalid.","triggerScenarios":"Calling AddAttribute/AddComponentParameter after AddContent, after CloseElement, after a reference capture, or at the root. Any sequence where _lastNonAttributeFrameType drifted away from Element/Component before an attribute append.","commonSituations":"Misordered manual tree construction. Source generators emitting attributes in the wrong slot. Custom component bases that emit parameters conditionally and miss the ordering invariant.","solutions":["Reorder so AddAttribute/AddComponentParameter immediately follows OpenElement/OpenComponent (or other attributes).","In custom code, track the last non-attribute frame type and re-open a scope before adding attributes if needed.","Use higher-level Razor/ComponentBase authoring instead of raw RenderTreeBuilder where possible."],"exampleFix":"// before\nbuilder.OpenElement(0, \"input\");\nbuilder.AddContent(1, \"text\");\nbuilder.AddAttribute(2, \"value\", x); // last non-attr frame is now content\n\n// after\nbuilder.OpenElement(0, \"input\");\nbuilder.AddAttribute(1, \"value\", x);\nbuilder.AddContent(2, \"text\");","handlingStrategy":"validation","validationCode":"if (lastNonAttributeFrameType != RenderTreeFrameType.Element &&\n    lastNonAttributeFrameType != RenderTreeFrameType.Component)\n    throw new InvalidOperationException(\"Open an element/component before adding attributes.\");\nbuilder.AddAttribute(seq, name, value);","typeGuard":"static bool CanAddAttributeAfter(RenderTreeFrameType last)\n    => last == RenderTreeFrameType.Element || last == RenderTreeFrameType.Component;","tryCatchPattern":null,"preventionTips":["Add attributes/parameters immediately after OpenElement/OpenComponent.","Avoid interleaving content/capture/region frames before attributes.","Prefer Razor authoring over raw RenderTreeBuilder to get correct ordering."],"tags":["blazor","render-tree-builder","attribute","ordering","frame-type"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}