Skip to main content

Fixed: error CA1852: Type 'WeatherForecast' can be sealed because it has no subtypes in its containing assembly and is not externally visible

· 6 min read
Jagdish Kumawat
Founder @ Dewiride

The first build of a brand-new .NET 10 Web API failed with error CA1852 on the template's own WeatherForecast record. The solution turns on Microsoft's recommended code-quality rules and treats warnings as errors, and one of those rules asks for types like this one to be sealed. Adding that one word fixes it.

What I Was Doing​

I was building the solution from How to Create a .NET C# Web API Solution with a Class Library with .NET SDK 10.0.403. Its Directory.Build.props applies strict rules to every project:

Directory.Build.props
<Project>
<!-- Build settings shared by every project in this folder and the folders below it. -->
<PropertyGroup>
<!-- Stop the build on any compiler, analyzer or NuGet warning, so problems get fixed early. -->
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!-- Turn on the recommended set of .NET code-quality rules for the newest SDK. -->
<AnalysisLevel>latest-recommended</AnalysisLevel>
<!-- Check the code-style rules in .editorconfig during the build, not only in the editor. -->
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>
</Project>

The API project came straight from dotnet new webapi, with its sample /weatherforecast endpoint still in Program.cs. I built the solution for the first time:

Terminal
dotnet build

What I Expected​

Build succeeded. The code was the template's, untouched.

What I Got​

Output
Restore complete (1.3s)
Dewiride.Inventory.Data net10.0 succeeded (1.4s) → src/Dewiride.Inventory.Data/bin/Debug/net10.0/Dewiride.Inventory.Data.dll
Dewiride.Inventory.Api net10.0 failed with 1 error(s) (0.8s)
/Users/you/projects/dewiride-inventory-api/src/Dewiride.Inventory.Api/Program.cs(36,8): error CA1852: Type 'WeatherForecast' can be sealed because it has no subtypes in its containing assembly and is not externally visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)

Build failed with 1 error(s) in 3.6s

A terminal where dotnet build succeeds for Dewiride.Inventory.Data but fails for Dewiride.Inventory.Api with error CA1852: Type 'WeatherForecast' can be sealed because it has no subtypes in its containing assembly and is not externally visible.

What I Checked​

Program.cs(36,8) means line 36, column 8. That's the template's record:

src/Dewiride.Inventory.Api/Program.cs (lines 36–39)
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

The record has no access modifier, so C# makes it internal: visible only inside this project. Nothing in the project inherits from it. Those are exactly the two conditions the message names.

The rule's page also answered why the template's own code fails. Its table says CA1852 is not "Enabled by default in .NET 10". It runs here because AnalysisLevel is set to latest-recommended, and TreatWarningsAsErrors turns its warning into an error. Without those two settings, the same template builds cleanly.

Why It Happens​

Microsoft's CA1852 page explains the rule: "When a type isn't accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance." A sealed type can't be inherited from, and that's what lets .NET make some calls to it faster.

The Fix​

The page's fix is short: "Mark the type as sealed". Change line 36:

src/Dewiride.Inventory.Api/Program.cs (lines 36–39)
sealed record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Records can be sealed like classes. Nothing else changes: the endpoint still returns the same JSON.

After the Fix​

Terminal
dotnet build
Output
Restore complete (0.6s)
Dewiride.Inventory.Data net10.0 succeeded (0.1s) → src/Dewiride.Inventory.Data/bin/Debug/net10.0/Dewiride.Inventory.Data.dll
Dewiride.Inventory.Api net10.0 succeeded (0.6s) → src/Dewiride.Inventory.Api/bin/Debug/net10.0/Dewiride.Inventory.Api.dll

Build succeeded in 1.5s

A terminal where dotnet build now succeeds for both Dewiride.Inventory.Data and Dewiride.Inventory.Api and prints Build succeeded.

The same rule applies to your own code: make internal classes and records sealed unless something inherits from them. In the solution guide, the sample is removed afterwards anyway, because the API doesn't need it.

Common Mistakes​

MistakeWhat happensDo this instead
Removing TreatWarningsAsErrors to get past itEvery future warning scrolls by unnoticedFix the code; keep the setting
Suppressing CA1852 for the whole projectThe rule stops helping with your own typesMark the type sealed
Sealing a type that something inherits fromThat code stops compilingOnly seal types with no subtypes, which is what the rule reports

Troubleshooting​

SymptomLikely causeFix
CA1852 on one of your own classesAn internal class with no subclassesAdd sealed
CA1852 doesn't appear on a public typeThe rule only covers types that aren't visible outside the projectNothing to fix
CA1852 stopped appearing after adding InternalsVisibleToThe page says the rule doesn't flag those types by default when the assembly exposes its internalsSee the page's ignore_internalsvisibleto option

FAQ​

Is it safe to suppress CA1852 instead?​

The page says it's "safe to suppress a warning if performance isn't a concern". Sealing is a one-word change and makes the intent clear, so fixing it is usually the better choice.

Why didn't the template ship with sealed?​

The template targets the default rule set, where CA1852 is off. The error only appears with the stricter latest-recommended level.

Conclusion​

error CA1852 is a recommended performance rule, turned into an error by TreatWarningsAsErrors. The template's WeatherForecast record is internal and has no subtypes, so mark it sealed, and the build succeeds.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.