{"record":{"id":"75ed9813dcf9ad95","repo":"dotnet/aspnetcore","slug":"valueless-attributes-may-only-be-added-immediately","errorCode":null,"errorMessage":"Valueless attributes may only be added immediately after frames of type Element","messagePattern":"Valueless attributes may only be added immediately after frames of type Element","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/Rendering/RenderTreeBuilder.cs","lineNumber":174,"sourceCode":"    /// <param name=\"textContent\">Content for the new text frame.</param>\n    public void AddContent(int sequence, object? textContent)\n        => AddContent(sequence, textContent?.ToString());\n\n    /// <summary>\n    /// <para>\n    /// Appends a frame representing a bool-valued attribute with value 'true'.\n    /// </para>\n    /// <para>\n    /// The attribute is associated with the most recently added element.\n    /// </para>\n    /// </summary>\n    /// <param name=\"sequence\">An integer that represents the position of the instruction in the source code.</param>\n    /// <param name=\"name\">The name of the attribute.</param>\n    public void AddAttribute(int sequence, string name)\n    {\n        if (_lastNonAttributeFrameType != RenderTreeFrameType.Element)\n        {\n            throw new InvalidOperationException($\"Valueless attributes may only be added immediately after frames of type {RenderTreeFrameType.Element}\");\n        }\n\n        _entries.AppendAttribute(sequence, name, ElementBoolTrueValue);\n    }\n\n    /// <summary>\n    /// <para>\n    /// Appends a frame representing a bool-valued attribute.\n    /// </para>\n    /// <para>\n    /// The attribute is associated with the most recently added element. If the value is <c>false</c> and the\n    /// current element is not a component, the frame will be omitted.\n    /// </para>\n    /// </summary>\n    /// <param name=\"sequence\">An integer that represents the position of the instruction in the source code.</param>\n    /// <param name=\"name\">The name of the attribute.</param>\n    /// <param name=\"value\">The value of the attribute.</param>\n    public void AddAttribute(int sequence, string name, bool value)","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Components/src/Rendering/RenderTreeBuilder.cs#L156-L192","documentation":"The RenderTreeBuilder.AddAttribute(int, string) overload adds a valueless (bool-true) attribute. It is only valid immediately after an Element frame (e.g., after OpenElement). The builder tracks the last non-attribute frame type and throws InvalidOperationException if it is not Element, because valueless attributes only make sense for HTML elements (e.g., <input disabled />), not components or other frame types.","triggerScenarios":"Calling builder.AddAttribute(sequence, \"disabled\") without a preceding OpenElement call, or after OpenComponent. This is usually a bug in manually written render code or in a custom RenderTreeBuilder-based component. In Razor, this corresponds to writing a valueless attribute on a component instead of an element.","commonSituations":"Manual RenderTreeBuilder code that calls AddAttribute(int, string) before OpenElement; custom C# render methods with incorrect ordering; accidentally using the two-argument AddAttribute overload (valueless) instead of the three-argument overload.","solutions":["Ensure AddAttribute(sequence, name) (valueless) is only called after OpenElement and before CloseElement.","Use the three-argument overload AddAttribute(sequence, name, value) for component parameters.","Check the call ordering in custom RenderTreeBuilder code: OpenElement must precede valueless attribute calls.","If targeting a component, pass the value explicitly with the typed overload."],"exampleFix":"// before\nbuilder.OpenComponent<MyComponent>(0);\nbuilder.AddAttribute(1, \"IsActive\"); // valueless on component -> throws\nbuilder.CloseComponent();\n\n// after\nbuilder.OpenComponent<MyComponent>(0);\nbuilder.AddAttribute(1, \"IsActive\", true); // explicit value\nbuilder.CloseComponent();","handlingStrategy":"validation","validationCode":"// Validate builder state before adding valueless attribute\nstatic void SafeAddValuelessAttribute(RenderTreeBuilder builder, int seq, string name)\n{\n    // The builder itself validates; this documents the contract\n    // Ensure you called OpenElement first\n    builder.AddAttribute(seq, name); // only valid after OpenElement\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always call OpenElement before using the valueless AddAttribute(int, string) overload.","Use the three-argument AddAttribute(int, string, object) overload for component parameters.","In manual render code, maintain strict ordering: OpenElement -> AddAttribute -> CloseElement.","Add code comments documenting when valueless attributes are valid."],"tags":["blazor","rendertreebuilder","attributes","element","manual-render"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}