{"record":{"id":"1586de2082315b9c","repo":"dotnet/aspnetcore","slug":"element-reference-captures-may-only-be-added-as-ch","errorCode":null,"errorMessage":"Element reference captures may only be added as children of frames of type Element","messagePattern":"Element reference captures may only be added as children of frames of type Element","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/Rendering/RenderTreeBuilder.cs","lineNumber":600,"sourceCode":"        // if necessary.\n        if (_hasSeenAddMultipleAttributes)\n        {\n            ProcessDuplicateAttributes(first: indexOfEntryBeingClosed + 1);\n        }\n\n        _entries.Buffer[indexOfEntryBeingClosed].ComponentSubtreeLengthField = _entries.Count - indexOfEntryBeingClosed;\n    }\n\n    /// <summary>\n    /// Appends a frame representing an instruction to capture a reference to the parent element.\n    /// </summary>\n    /// <param name=\"sequence\">An integer that represents the position of the instruction in the source code.</param>\n    /// <param name=\"elementReferenceCaptureAction\">An action to be invoked whenever the reference value changes.</param>\n    public void AddElementReferenceCapture(int sequence, Action<ElementReference> elementReferenceCaptureAction)\n    {\n        if (GetCurrentParentFrameType() != RenderTreeFrameType.Element)\n        {\n            throw new InvalidOperationException($\"Element reference captures may only be added as children of frames of type {RenderTreeFrameType.Element}\");\n        }\n\n        _entries.AppendElementReferenceCapture(sequence, elementReferenceCaptureAction);\n        _lastNonAttributeFrameType = RenderTreeFrameType.ElementReferenceCapture;\n    }\n\n    /// <summary>\n    /// Appends a frame representing an instruction to capture a reference to the parent component.\n    /// </summary>\n    /// <param name=\"sequence\">An integer that represents the position of the instruction in the source code.</param>\n    /// <param name=\"componentReferenceCaptureAction\">An action to be invoked whenever the reference value changes.</param>\n    public void AddComponentReferenceCapture(int sequence, Action<object> componentReferenceCaptureAction)\n    {\n        var parentFrameIndex = GetCurrentParentFrameIndex();\n        if (!parentFrameIndex.HasValue)\n        {\n            throw new InvalidOperationException(ComponentReferenceCaptureInvalidParentMessage);\n        }","sourceCodeStart":582,"sourceCodeEnd":618,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Components/src/Rendering/RenderTreeBuilder.cs#L582-L618","documentation":"Thrown by RenderTreeBuilder.AddElementReferenceCapture (the frame emitted for an HTML-element @ref capture). The capture frame is a child of its parent frame, and the parent must be an Element frame opened via OpenElement. The render-tree diff requires the captured reference to resolve to a real DOM element, so any other parent type (Component, Region, or no parent) is an invariant violation.","triggerScenarios":"Calling builder.AddElementReferenceCapture(seq, action) when GetCurrentParentFrameType() != Element — i.e., at the root of a render fragment (empty stack), inside OpenComponent(...)/CloseComponent(), or inside OpenRegion(...)/CloseRegion(). The .razor compiler emits this via @ref on an HTML tag; the manual-call equivalent is misplaced.","commonSituations":"Hand-written RenderFragment/Razor lib code that forgets OpenElement before the capture; a mismatched CloseElement that popped the element before the capture ran; a refactor that moved an @ref onto a component instead of an element.","solutions":["Ensure AddElementReferenceCapture is called strictly between OpenElement(...) and its matching CloseElement().","Audit every Open*/Close* pair in the RenderFragment for balance — an early CloseElement is the usual cause.","If authoring .razor, confirm the @ref is on an HTML element (<input @ref=...>) and not on a component (<MyComp @ref=...> uses AddComponentReferenceCapture instead)."],"exampleFix":"// before\nbuilder.AddElementReferenceCapture(1, r => _ref = r);\nbuilder.OpenElement(0, \"input\");\n...\nbuilder.CloseElement();\n\n// after\nbuilder.OpenElement(0, \"input\");\n...\nbuilder.AddElementReferenceCapture(1, r => _ref = r);\nbuilder.CloseElement();","handlingStrategy":"validation","validationCode":"// RenderTreeBuilder has no public parent-type accessor. In manual RenderFragment\ncode, track your own nesting depth to guarantee the capture runs inside an element.\nint _elementDepth = 0;\nvoid Render(RenderTreeBuilder b) {\n    b.OpenElement(0, \"input\"); _elementDepth++;\n    if (_elementDepth > 0) b.AddElementReferenceCapture(1, r => _ref = r);\n    _elementDepth--; b.CloseElement();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call AddElementReferenceCapture outside an OpenElement/CloseElement pair.","Keep element-ref captures immediately after the OpenElement they target, before any child content.","In .razor, only put @ref on HTML elements; for components use component @ref (handled by a different API)."],"tags":["blazor","rendering","rendertree","element-reference","manual-renderfragment"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}