Sorry, this should have been filed at dotnet/roslyn
Summary
After upgrading from .NET SDK 10.0.203 → 10.0.300, the Razor source generator falsely reports RZ1021: Markup in a code block must start with a tag and all start tags must be matched with end tags for perfectly valid markup. The generated .g.cs is corrupted: the parser eats the leading <tagname and emits everything after as raw C#, which then triggers cascading CS0102/CS9348/CS0101 errors across the whole assembly.
The trigger is surprisingly narrow:
- The element must be inside a Razor code block (
@if {}, @foreach {}, …).
- The enclosing block must be inside outer markup (e.g. a
<div>).
- The tag name must be 4 or more characters (3-char names like
<br>, <img>, <hr>, <col>, <wbr> work fine).
- The element's line must be tab-indented or have no indentation. Space indentation works.
Minimal repro
Views/Home/Repro.cshtml:
<div>
@if (true)
{
<input />
}
</div>
(All indentation is tabs.) Build with dotnet build:
Views/Home/Repro.cshtml(4,5): error RZ1021: Markup in a code block must start with a tag and all start tags must be matched with end tags. Do not use unclosed tags like "<br>". Instead use self-closing tags like "<br/>".
Followed by ~10 cascading CS errors in the generated _Repro_cshtml.g.cs.
What makes it succeed
UPDATE: Spoilered, because @Magehernan encountered this in a scenario that did not match my findings.
- It occurred for simple
<div> tags, no need for 4+ characters
- It occurred without an outer
<div> tag.
Any one of the following changes makes the build succeed:
- Replace tab indentation with spaces.
- Use a tag name with ≤ 3 characters (
<br />, <img />, <hr />, <col />, <wbr />).
- Remove the outer
<div> wrapper.
- Disable the source generator:
<UseRazorSourceGenerator>false</UseRazorSourceGenerator>.
Tag name length matrix (with tab indent, inside <div> + @if)
| Tag |
Result |
<a />, <ab />, <abc /> |
OK |
<abcd />, <abcde /> |
RZ1021 |
<br />, <img />, <hr />, <col />, <wbr /> |
OK |
<input />, <meta />, <link />, <area />, <base />, <embed />, <source />, <track /> |
RZ1021 |
Tag with hyphen (<aaa-bbb-ccc />) |
OK |
So this is not about void elements specifically (otherwise <br> and <input> would behave the same); the discriminator looks like raw tag-name length combined with leading whitespace classification.
Inspecting the generated file
With EmitCompilerGeneratedFiles=true, the generated _Repro_cshtml.g.cs shows the parser bailed early — it emits <input as the start of a markup element, then puts the rest of the line and following lines as raw C# code inside a method body, producing a stream of <invalid-global-code> types that conflict with every other Razor file in the assembly. Because the cascading CS errors land in AspNetCoreGeneratedDocument, a single bad .cshtml makes every other view in the project fail to compile (CS0101, CS0102 for ModelExpressionProvider/Url/Component/Json/Html).
Environment
- SDK:
.NET SDK 10.0.300 (commit caa81fa497)
- OS: Debian 13 (Linux x64)
- Previously working: 10.0.203
- Affected project:
Microsoft.NET.Sdk.Web, <TargetFramework>net10.0</TargetFramework>
- Reproduces in both
Debug and Release configurations.
- Reproduces without any tag helper imports (removing
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers does not fix it).
Impact
This silently broke a real production project after a system-wide SDK update. The error message (Do not use unclosed tags like "<br>") is actively misleading because the actual markup is well-formed self-closed <input />, and <br> itself is one of the tags that does not trigger it. A single offending file cascades into 100+ CS errors across the project, making it hard to identify the root cause without inspecting the generated source.
Workaround
<PropertyGroup>
<UseRazorSourceGenerator>false</UseRazorSourceGenerator>
</PropertyGroup>
Sorry, this should have been filed at dotnet/roslyn
Summary
After upgrading from .NET SDK 10.0.203 → 10.0.300, the Razor source generator falsely reports
RZ1021: Markup in a code block must start with a tag and all start tags must be matched with end tagsfor perfectly valid markup. The generated.g.csis corrupted: the parser eats the leading<tagnameand emits everything after as raw C#, which then triggers cascading CS0102/CS9348/CS0101 errors across the whole assembly.The trigger is surprisingly narrow:
@if {},@foreach {}, …).<div>).<br>,<img>,<hr>,<col>,<wbr>work fine).Minimal repro
Views/Home/Repro.cshtml:(All indentation is tabs.) Build with
dotnet build:Followed by ~10 cascading CS errors in the generated
_Repro_cshtml.g.cs.What makes it succeed
UPDATE: Spoilered, because @Magehernan encountered this in a scenario that did not match my findings.- It occurred for simple
- It occurred without an outer
<div>tags, no need for 4+ characters<div>tag.Any one of the following changes makes the build succeed:
<br />,<img />,<hr />,<col />,<wbr />).<div>wrapper.<UseRazorSourceGenerator>false</UseRazorSourceGenerator>.Tag name length matrix (with tab indent, inside
<div>+@if)<a />,<ab />,<abc /><abcd />,<abcde /><br />,<img />,<hr />,<col />,<wbr /><input />,<meta />,<link />,<area />,<base />,<embed />,<source />,<track /><aaa-bbb-ccc />)So this is not about void elements specifically (otherwise
<br>and<input>would behave the same); the discriminator looks like raw tag-name length combined with leading whitespace classification.Inspecting the generated file
With
EmitCompilerGeneratedFiles=true, the generated_Repro_cshtml.g.csshows the parser bailed early — it emits<inputas the start of a markup element, then puts the rest of the line and following lines as raw C# code inside a method body, producing a stream of<invalid-global-code>types that conflict with every other Razor file in the assembly. Because the cascading CS errors land inAspNetCoreGeneratedDocument, a single bad.cshtmlmakes every other view in the project fail to compile (CS0101, CS0102 forModelExpressionProvider/Url/Component/Json/Html).Environment
.NET SDK 10.0.300(commitcaa81fa497)Microsoft.NET.Sdk.Web,<TargetFramework>net10.0</TargetFramework>DebugandReleaseconfigurations.@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpersdoes not fix it).Impact
This silently broke a real production project after a system-wide SDK update. The error message (
Do not use unclosed tags like "<br>") is actively misleading because the actual markup is well-formed self-closed<input />, and<br>itself is one of the tags that does not trigger it. A single offending file cascades into 100+ CS errors across the project, making it hard to identify the root cause without inspecting the generated source.Workaround