C# – How to treat warnings like errors

Warnings are easy to ignore and forget about, which isn’t good. They point out potential problems that you might want to fix. To make it easier to pay attention to warnings, you can treat them like errors.

You can choose which warnings to treat like errors by using settings in the project file (or in a props file). There are two approaches:

  • Include specific warnings with WarningsAsErrors.
  • Include all warnings with TreatWarningsAsErrors, and exclude specific warnings with WarningsNotAsErrors. Note: You can exclude all analyzer warnings with CodeAnalyisTreatWarningsAsErrors.

When these warnings show up as errors, you have the option to fix or suppress them. You aren’t required to fix them every time. The point of this is to help make sure you look at potential problems and decide what to do about them.

In this article, I’ll show examples of using these settings.

Treat specific warnings like errors

When you want to specify exactly which warnings to treat like errors, you can use WarningsAsErrors. Here’s an example of specifying two different warnings:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <AnalysisLevel>latest-recommended</AnalysisLevel>
        <WarningsAsErrors>CS8602,CA2241</WarningsAsErrors>
    </PropertyGroup>

</Project>
Code language: HTML, XML (xml)

With this approach, you can specify warnings that you know you’ll need to fix (or at least take a look at). For example, consider the following code (which has an intentional error):

var name = GetName();

if (name.Length > 5) //Error CS8602
{
    var greeting = string.Format("Hello {0}"); //Error CA2241 and Warning CA1305
    Console.WriteLine(greeting);
}

string? GetName()
{
    return null;
}
Code language: C# (cs)

Note: I’m using string.Format() instead of string interpolation here because it’s an easy way to cause warnings. I suggest always trying to use string interpolation.

Because CS8602 and CA2241 were added to WarningsAsErrors, they are showing up as errors. Meanwhile CA1305 continues to show as a warning. Because this is showing errors, you have to deal with them and decide if you want to fix or suppress them (in this example, the code definitely needs to be fixed!).

Warning: VS ignores WarningsAsErrors when launching your project

If you do a build, errors from WarningsAsErrors break the build, which is expected. However, when you try to launch your project in Visual Studio (like with Start Without Debugging), the errors from WarningsAsErrors are ignored and don’t prevent it from launching. This is unexpected, undesirable, and probably a bug. For comparison, when you use TreatWarningsAsErrors, VS works as expected and won’t launch if there’s an error.

For reference: I ran into this problem while using VS 2022 version 17.2.6.

Treat all warnings like errors, excluding specific warnings

You can use TreatWarningsAsErrors to treat ALL warnings like errors, and then exclude specific warnings with WarningsNotAsErrors. Here’s an example of using these settings:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <AnalysisLevel>latest-recommended</AnalysisLevel>
        <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
        <WarningsNotAsErrors>CA1305</WarningsNotAsErrors>
    </PropertyGroup>

</Project>

Code language: HTML, XML (xml)

This approach allows you to aggressively deal with warnings, either by fixing the problems, suppressing them, or excluding the warning from being treated like an error. This is a key difference from the other approach – you are forced to make a decision about every single warning you run into. Here’s an example of the effects of using these settings. This is using the same code as before:

var name = GetName();

if (name.Length > 5) //Error CS8602
{
    var greeting = string.Format("Hello {0}"); //Error CA2241 and Warning CA1305
    Console.WriteLine(greeting);
}

string? GetName()
{
    return null;
}
Code language: C# (cs)

With TreatWarningsAsErrors, all warnings are treated like errors except for the excluded ones. This is why CS8602 and CA2241 automatically show up as errors, while CA1305 continues to show up as a warning (because it was excluded).

Exclude analyzer warnings

TreatWarningsAsErrors includes analyzer warnings. If you want, you can exclude all analyzer warnings with CodeAnalysisTreatWarningsAsErrors, like this:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <AnalysisLevel>latest-recommended</AnalysisLevel>
        <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
        <CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>

    </PropertyGroup>

</Project>

Code language: HTML, XML (xml)

Note: I’m using the built-in .NET analyzers.

Suppress a warning

When you treat warnings like errors, they aren’t exactly like regular errors. You have the option of fixing them or suppressing them. You can suppress them just like any other warnings by using a pragma:

#pragma warning disable CS0168 // Variable is declared but never used
string name;
#pragma warning restore CS0168 // Variable is declared but never used
Code language: C# (cs)

Note: To have Visual Studio generate this for you, right-click > Quick Actions > Suppress > In Source.

This makes it stop showing CS0168 for this line.

When you use TreatWarningsAsErrors, you’re forced to deal with every single warning, which means you might end up suppressing a warning over and over. This can be tedious and clutter the code. If you know you aren’t going to ever fix this warning, and don’t want it to even show up as a warning, then you can get rid of the warning with NoWarn. Use with caution. Here’s an example:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <AnalysisLevel>latest-recommended</AnalysisLevel>
        <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
        <NoWarn>CS0168</NoWarn>

    </PropertyGroup>

</Project>

Code language: HTML, XML (xml)