Skip to content

/flags/csharp/dotnet-build-warnaserror

dotnet build -warnaserror / TreatWarningsAsErrors: fail the C# build on warnings

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 10.0.401updated
tool
C#
command
dotnet build
flag
-warnaserror[:codes], -p:TreatWarningsAsErrors=true
default
off: warnings are printed and the build succeeds

dotnet build -warnaserror makes the build fail when any warning is reported; -warnaserror:CS8602 does it only for the listed codes. The project-file equivalent is <TreatWarningsAsErrors>true</TreatWarningsAsErrors> (or -p:TreatWarningsAsErrors=true on the command line), with <WarningsAsErrors> for specific codes and <NoWarn> to suppress codes entirely. Teams usually set them in CI or in Directory.Build.props so that warnings cannot pile up.

Default, all warnings, one code

bash
dotnet new console -n App -o . >/dev/null 2>&1
cat > Program.cs <<'EOF'
string? name = args.Length > 0 ? args[0] : null;
Console.WriteLine(name.Length);
class Person { public string Name { get; set; } }
EOF
build() { dotnet build --no-incremental "$@" 2>&1 | grep -oE "(warning|error) CS[0-9]+[^[]*" | sort -u; echo "exit: ${PIPESTATUS[0]}"; }
echo "== default"
build
echo "== -warnaserror"
build -warnaserror
echo "== -warnaserror:CS8602"
build -warnaserror:CS8602
echo "== -p:TreatWarningsAsErrors=true -p:NoWarn=CS8618"
build -p:TreatWarningsAsErrors=true -p:NoWarn=CS8618

Output

== default
warning CS8602: Dereference of a possibly null reference.
warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
exit: 0
== -warnaserror
error CS8602: Dereference of a possibly null reference.
error CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
exit: 1
== -warnaserror:CS8602
error CS8602: Dereference of a possibly null reference.
warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
exit: 1
== -p:TreatWarningsAsErrors=true -p:NoWarn=CS8618
error CS8602: Dereference of a possibly null reference.
exit: 1

By default both nullable warnings are printed and the build succeeds (exit 0). -warnaserror turns both into errors and the build fails with exit 1. With a code list only CS8602 becomes an error and CS8618 stays a warning. NoWarn removes CS8618 entirely, so with TreatWarningsAsErrors only CS8602 fails the build.

The settings

SettingScopeEffect
dotnet build -warnaserrorMSBuild switch, this buildEvery warning (compiler, MSBuild, NuGet) becomes an error
dotnet build -warnaserror:CS8602;CS8618MSBuild switch, this buildOnly the listed codes become errors
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>Project propertyAll compiler and analyzer warnings become errors
<WarningsAsErrors>CS8602;CS8618</WarningsAsErrors>Project propertyOnly the listed codes become errors; Nullable is a shortcut for all nullable warnings
<WarningsNotAsErrors>CS0618</WarningsNotAsErrors>Project propertyExceptions to TreatWarningsAsErrors: stay warnings
<NoWarn>$(NoWarn);CS1591</NoWarn>Project propertySuppress the codes completely
-warnAsMessage:codesMSBuild switchDowngrade the listed codes to messages
#pragma warning disable CS8602Source fileSuppress in a region of code

Append to existing lists with $(NoWarn); and $(WarningsAsErrors); so that values from Directory.Build.props or the SDK are not lost.

A typical setup

Directory.Build.props
<Project>
  <PropertyGroup>
    <Nullable>enable</Nullable>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <!-- obsolete APIs: report, do not fail -->
    <WarningsNotAsErrors>$(WarningsNotAsErrors);CS0618</WarningsNotAsErrors>
    <!-- missing XML comments on public members -->
    <NoWarn>$(NoWarn);CS1591</NoWarn>
  </PropertyGroup>
</Project>

On a large legacy code base, start with <WarningsAsErrors>Nullable</WarningsAsErrors> or a short list of codes, fix them, and widen the list over time. See Nullable=enable for the nullable warnings themselves.

Pitfalls

  • An SDK or analyzer update can add new warnings; with TreatWarningsAsErrors that breaks the build. Pin the SDK with global.json and the analyzer level with <AnalysisLevel>.
  • Real compile errors such as CS1061 are errors in any case; these settings only change warnings.
  • Incremental builds can skip the compiler after a property change on the command line; add --no-incremental when trying settings, as the example does.
  • NoWarn hides a warning for everyone. Prefer fixing the code, or a #pragma on the one line that needs it.

FAQ

What is the difference between -warnaserror and -p:TreatWarningsAsErrors=true?

-warnaserror is an MSBuild switch: it promotes every warning logged during the build, including MSBuild and NuGet warnings, to an error. TreatWarningsAsErrors is a project property passed to the C# compiler and analyzers, so it affects CS and analyzer warnings. In CI both fail the build; the MSBuild switch is broader.

How do I keep one warning as a warning while treating the rest as errors?

Use WarningsNotAsErrors in the project file, for example <WarningsNotAsErrors>CS0618</WarningsNotAsErrors> together with <TreatWarningsAsErrors>true</TreatWarningsAsErrors>. To hide a warning completely, use NoWarn instead.

Why does my build fail on warnings only in Release?

The property is probably inside a PropertyGroup with a Condition on the configuration, for example Condition="'$(Configuration)' == 'Release'". Search the .csproj and Directory.Build.props for TreatWarningsAsErrors.

Sources