{"record":{"id":"efbf81741734568b","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 Element or Component","messagePattern":"Attributes may only be added immediately after frames of type Element or Component","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/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Components/src/Rendering/RenderTreeBuilder.cs#L706-L742","documentation":"Thrown by the private AssertCanAddAttribute guard invoked by AddAttribute/AddMultipleAttributes. Attributes are only valid immediately after an Element or Component frame (the last non-attribute frame must be Element or Component); text, markup, region, reference-capture, and named-event frames cannot receive attributes.","triggerScenarios":"Calling builder.AddAttribute(seq, name, value) after AddContent/AddMarkupContent/OpenRegion/AddElementReferenceCapture/AddNamedEvent — i.e., when _lastNonAttributeFrameType is not Element or Component. In .razor this maps to an attribute appearing after literal text or inside a region instead of directly on the tag.","commonSituations":"A misplaced attribute in hand-written RenderFragment after a text node; a conditional that emits text before the attribute; code generation that interleaves attributes with content frames.","solutions":["Emit all AddAttribute calls directly after OpenElement/OpenComponent and before any child content/text.","If attributes are computed after content, restructure so attributes are added first or re-open the element/component.","Check that no AddContent/AddMarkupContent/OpenRegion runs between the open and the attribute."],"exampleFix":"// before\nbuilder.OpenElement(0, \"div\");\nbuilder.AddContent(1, \"hello\");\nbuilder.AddAttribute(2, \"class\", \"x\");\nbuilder.CloseElement();\n\n// after\nbuilder.OpenElement(0, \"div\");\nbuilder.AddAttribute(1, \"class\", \"x\");\nbuilder.AddContent(2, \"hello\");\nbuilder.CloseElement();","handlingStrategy":"validation","validationCode":"// Emit attributes immediately after OpenElement/OpenComponent and before any content frame.\nvoid RenderDiv(RenderTreeBuilder b) {\n    b.OpenElement(0, \"div\");\n    b.AddAttribute(1, \"class\", _cls);   // attributes first\n    b.AddContent(2, _text);            // then content\n    b.CloseElement();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Order frames: open -> attributes -> children -> close; never interleave attributes with content.","In loops building attributes, keep them contiguous before the first child frame.","Use AddContent/AddMarkupContent only after all attributes are added."],"tags":["blazor","rendering","rendertree","attributes","manual-renderfragment"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}