C# Nullability issues not reported

Must-share information (formatted with Markdown):

  • SonarQube Server Data Center Edition v2025.5 (113872)

I have code which raises a CS8604 diagnostic Resolve nullable warnings - C# reference | Microsoft Learn

My Directory.Build.props contains

<PropertyGroup>
    <WarningsAsErrors>Nullable</WarningsAsErrors>
</PropertyGroup>

Additionally I added to my .editorconfig

dotnet_diagnostic.CA8604.severity = error

Wenn I build with dotnet build MySolution.sln (.NET 10), the build fails. If however I run with

$env:URL="..."
$env:SONAR_TOKEN="..."
$env:SONAR_PROJECT_KEY="..."

dotnet tool install --global dotnet-sonarscanner

dotnet sonarscanner begin /d:sonar.host.url="$env:URL" /k:$env:SONAR_PROJECT_KEY /d:sonar.token=$env:SONAR_TOKEN

dotnet build --no-incremental --nologo MySolution.sln

dotnet sonarscanner end /d:sonar.token=$env:SONAR_TOKEN

Then the build doesn’t fail.

I’m having a hard time figuring out, what SonarQube actually does, what changes the behavior. Shouldn’t explicit diagnostic levels in the .editorconfig overrule whatever SonarQube does?

How can I find out, why the error is suppressed?

Neither In the .sonarqube directory inside my working directory nor in the C:\Users\<MyUser>\AppData\Local\Temp.sonarqube there is any mention of CA8604 anywhere.

Any suggestions how to figure out, why the diagnostic is swallowed?

Does your build fail locally? Does <WarningsAsErrors>Nullable</WarningsAsErrors> do what you think it does?

Hi,

Per the docs (see the notice at the bottom of the section):

 
HTH,
Ann

1 Like

Still, if there are nullabillity warnings, you should see them in your local output. <WarningsAsErrors> only changes the level of the issue.

Yes, it fails locally.

It shouldn’t matter, that WarningsAsErrors` is turned off, because the issues are configured to be errors.

Concerning the CodeAnalysisRuleSet: I found data in <workdirectory>\.sonarqube and %TEMP%\.sonarqube, but nothing in there contains CS8604. Are other directories involved?

It still is strange as those warnings come directly from the compiler, and are not part of the set of warnings that SonarCloud alters.

Hi @carlossus,

The behavior you’re seeing is by design. The SonarScanner for .NET explicitly clears both TreatWarningsAsErrors and WarningsAsErrors during the scan build, with the comment “Make sure no warnings are treated as errors” (source). This was introduced back in 2015 to prevent injected Roslyn analyzers from failing the build — the scanner needs the build to complete successfully in order to collect all analysis results. Issues are then surfaced through the SonarQube quality gate rather than via build failure.

There’s also a separate issue with your .editorconfig entry: dotnet_diagnostic.CA8604.severity = error has no effect because the diagnostic ID is wrong. The CA prefix is for Roslyn analyzer rules; C# compiler nullable warnings use the CS prefix, so the correct ID would be dotnet_diagnostic.CS8604.severity = error. However, even with the correct ID, the scanner would still override it for the same reason above.

If you want CS8604 violations to block delivery, the right place to enforce that is through the SonarQube quality gate — configure the corresponding rule in your quality profile and set the gate to fail on new issues of that severity.

2 Likes

Hi @Martin_Strecker

Thanks for your detailed answer:

Sorry for getting the ID wrong, we actually use dotnet_analyzer_diagnostic.category-Nullable.severity = warning, got confused.

Setting the severity works fine for many external analyzers (Meziantou.Analyzer, AwesomeAssertions.Analyzers, etc), and also for many Microsoft analyzers (definitely for IDE0005). Why the discrepancy between different external analyzers?

Using only the quality gate currently doesn’t work for us, because we are scanning only new code, and issues may appear in other places. I also haven’t found how I would include Microsoft’s Nullability analyzer warnings in the SonarQube quality gate. They aren’t available in the “Rules” section, so how would I set their severity?

IDE* rules are not run when building from the command-line (only run when buidling within Visual Studio), so those should never show up in SonarQube.

Nullable is best set per project or (even better) in the Directory.Build.props file:

<Project>

  <PropertyGroup>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

IDE* rules are not run when building from the command-line (only run when buidling within Visual Studio), so those should never show up in SonarQube.

They are run. E.g. using

.editorconfig

root = true
[*.cs]
# Remove unused namespaces
dotnet_diagnostic.IDE0005.severity = error

Program.cs

using System.Reflection;
System.Console.WriteLine("Hello World!");

and .csproj file

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
</Project>

Nullable is best set per project or (even better) in the Directory.Build.props file:

<Project>

  <PropertyGroup>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

Of course we do that. But the diagnostics are about making sure, that the nullability is respected:

The IDE rules are not available as separate Roslyn Analyzers, so you can state the error level as you like, but the compiler has no excess to them when compiling (outside the VS environment, and SonarQube runs outside VS).

<Nullable>enable</Nullable> is sufficient, the rest does only add noise to your configuration.

For the <EnforceCodeStyleInBuild>, it seems that there issue with that as well, wen running them: EnforceCodeStyleInBuild does not cause the build to fail although errors are present · Issue #49439 · dotnet/roslyn · GitHub

The IDE rules are not available as separate Roslyn Analyzers, so you can state the error level as you like, but the compiler has no excess to them when compiling (outside the VS environment, and SonarQube runs outside VS).

My example was outside of the VS environment, simply running dotnet build wherever you like and you get a failing build. Here the output when running on WSL:

Nullability.zip (999 Bytes)

<Nullable>enable</Nullable> is sufficient, the rest does only add noise to your configuration.

Well, that doesn’t take care of the diagnostics which arise due to this configuration.

Example: You change the return value of one method from string? to string. Then some consumer, which wasn’t adapted, gets a new diagnostics. However, because only the method was changed, the actual place where the diagnostic pops up isn’t covered by “new code” and the issues slips in.

And also when running analysis on the overall code, the nullability issue appears as “Code smell: Medium”. This rule, however can’t be configured for the full project. Or am I missing something?

For the <EnforceCodeStyleInBuild>, it seems that there issue with that as well, wen running them: EnforceCodeStyleInBuild does not cause the build to fail although errors are present · Issue #49439 · dotnet/roslyn · GitHub

And thanks for that link. According to roslyn/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs at main · dotnet/roslyn · GitHub, IDE0005 appears as “HighlyRecommended” and is active if explicitely enabled (like I did)

On IDE rules outside Visual Studio: @Corniel’s statement that IDE rules don’t run outside Visual Studio is not accurate in the general case. With <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>, the Roslyn compiler host loads IDE analyzer assemblies during dotnet build, so rules like IDE0005 produce diagnostics in a plain command-line build — exactly as you demonstrated, @carlossus. The linked Roslyn issue #49439 refers to specific edge cases, not a blanket limitation.

On the new code gap: This is by design and not specific to nullability — it applies to any rule whose analysis spans multiple files, such as data flow or type inference rules. SonarQube’s new code detection is line-based: if a line wasn’t changed, it’s not new code, even if a change elsewhere causes a new issue to appear on it. The practical approach is to switch to an overall code quality gate once you have a clean baseline — issues are then caught regardless of which file was touched.

On CS8603 not being configurable: CS8603 is a C# compiler diagnostic, not a native Sonar rule. SonarQube imports it as an external issue during analysis, which is why it appears with a fixed “Code smell: Medium” classification — configuring external issues through the Quality Profile is a known limitation. The overall quality gate approach above applies here as well.

Running two separate builds is another option worth considering: run one build outside the scanner — for example as part of your unit test or release artifact step — where WarningsAsErrors is intact and nullable warnings like CS8603 will fail the build as expected; then run a second build wrapped in sonarscanner begin/end purely for analysis. This gives you both hard enforcement and SonarQube reporting without compromise.

Configuring external issues through the Quality Profile is a known limitation. The overall quality gate approach above applies here as well.

Ok, thanks for the confirmation.

I’m in a legacy environment and trying to fix one issue after the other. Usually I increase the severity of single diagnostics I fixed in the overall code.

So it would’ve been nice to enforce nullability issues in some way without changing the quality gate itself, which would again include more issues which aren’t cleaned up, yet.

Running two separate builds is another option worth considering: run one build outside the scanner — for example as part of your unit test or release artifact step — where WarningsAsErrors is intact and nullable warnings like CS8603 will fail the build as expected; then run a second build wrapped in sonarscanner begin/end purely for analysis. This gives you both hard enforcement and SonarQube reporting without compromise.

I guess that’s something I’ll need to consider.

Thank you and thanks to @Corniel for the discussion!

Well, that is good to know! Thanks for sharing this.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.