Guides authoring of MSBuild errors, warnings, and diagnostic messages. Consult when adding new MSBxxxx codes, writing or modifying user-facing diagnostic text, deciding between error/warning/message severity, working with Strings.resx resource files, formatting paths in error output, or evaluating whether a new warning could break WarnAsError builds.
Error messages are MSBuild's primary user interface. They must help developers fix problems without reading source code.
For the mechanics of error code assignment, see assigning-msb-error-code.md.
Every error message must answer three questions:
<!-- BAD: What is "it"? What should I do? -->
<value>MSB4999: Invalid configuration.</value>
<!-- GOOD: States the problem, context, and fix -->
<value>MSB4999: The project "{0}" specifies TargetFramework "{1}" which is not installed. Install the SDK for "{1}" or update the TargetFramework in the project file.</value>
Is the condition always wrong (invalid input, impossible state)?
├── Yes → ERROR (build should fail)
└── No
├── Could this cause subtle build correctness issues?
│ ├── Yes, likely → WARNING (but see WarnAsError impact below)
│ └── Yes, maybe → MESSAGE at Normal importance
└── Is this purely informational?
└── Yes → MESSAGE at Low importance
New warnings are breaking changes for builds using:
-WarnAsError (CLI)<TreatWarningsAsErrors>true</TreatWarningsAsErrors> (project)<WarningsAsErrors>MSBxxxx</WarningsAsErrors> (specific codes)Before adding a new warning, consider:
| Range | Area |
|---|---|
MSB1xxx | Command-line handling |
MSB3xxx | Tasks (Microsoft.Build.Tasks.Core.dll) |
MSB4xxx | Engine (Microsoft.Build.dll) |
MSB5xxx | Shared code across assemblies |
MSB6xxx | Utilities (Microsoft.Build.Utilities) |
Strings.resx file for the appropriate assemblySee assigning-msb-error-code.md for detailed steps.
<data name="FeatureArea.DescriptiveName">
<value>MSBxxxx: Clear description with {0} placeholders for runtime values.</value>
<comment>{StrBegin="MSBxxxx: "}{0} is the project file path. {1} is the property name.</comment>
</data>
FeatureArea.DescriptiveName conventionMSBxxxx: (code, colon, space){StrBegin} marker and explains each {N} placeholderUse the standard formatting method that extracts and applies the error code:
// For errors
Log.LogErrorWithCodeFromResources("Copy.Error", sourceFile, destFile, ex.Message);
// For warnings
Log.LogWarningWithCodeFromResources("ResolveAssemblyReference.Conflict", assemblyName);
// For engine-level errors (not in tasks)
ProjectFileErrorUtilities.ThrowInvalidProjectFile(
elementLocation,
"InvalidProjectFile",
arg1, arg2);
Never construct error messages by string concatenation — always use resource strings for localization support.
MSBxxxx) are never localized.xlf placeholder translations<comment> elements to help translators understand contextIElementLocation when available — this enables IDE click-to-navigateStrings.resx range{StrBegin} comment and placeholder documentation added.xlf files