From dotnet-skills
Interpreting MSBuild output, NuGet errors, or analyzer warnings. Error codes, CI drift fixes.
npx claudepluginhub wshaddix/dotnet-skillsThis skill uses the workspace's default tool permissions.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Help agents interpret and act on MSBuild build output. Covers error code prefixes, NuGet restore failures, analyzer warning interpretation, multi-targeting build differences, and "works locally, fails in CI" diagnosis patterns. Each subsection includes example output, diagnosis steps, and a fix pattern.
Out of scope: Writing or modifying .csproj files (owned by [skill:dotnet-csproj-reading]). Project structure decisions (owned by [skill:dotnet-project-structure]). Common agent code mistakes (owned by [skill:dotnet-agent-gotchas]).
.NET 8.0+ SDK. MSBuild (included with .NET SDK). Understanding of SDK-style project format.
Cross-references: [skill:dotnet-agent-gotchas] for common code mistakes that cause build errors, [skill:dotnet-csproj-reading] for project file structure and modification, [skill:dotnet-project-structure] for project organization and SDK selection.
MSBuild output uses standardized prefixes to indicate the error source. Understanding the prefix tells you which system produced the error and where to look for fixes.
Produced by the Roslyn C# compiler. These are language-level issues in source code.
Example output:
src/MyApp.Api/Services/OrderService.cs(42,17): error CS0246: The type or namespace name 'OrderDto' could not be found (are you missing a using directive or an assembly reference?)
src/MyApp.Api/Models/User.cs(15,9): 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.
Diagnosis:
src/MyApp.Api/Services/OrderService.cs line 42, column 17.required modifier, nullable annotation (string?), or constructor initialization.Fix pattern:
using directives, fix type names, add missing references.required modifiers. Do NOT suppress with #pragma or ! operator.Produced by the MSBuild build engine itself. These indicate project file problems, target failures, or build system misconfiguration.
Example output:
error MSB4019: The imported project "C:\Program Files\dotnet\sdk\9.0.100\Microsoft\VisualStudio\v17.0\WebApplications\Microsoft.WebApplication.targets" was not found. Confirm that the expression in the Import declaration "..." is correct.
error MSB3644: The reference assemblies for .NETFramework,Version=v4.8 were not found. You might need to install the developer pack for this framework version.
Diagnosis:
.targets file is missing. This usually means wrong SDK type, missing workload, or corrupt SDK installation.Fix pattern:
<Project Sdk="..."> is correct (e.g., Microsoft.NET.Sdk.Web for ASP.NET Core). Run dotnet workload list and install missing workloads.<TargetFramework> value. Ensure the required SDK or targeting pack is installed.Produced by the NuGet package manager during restore or pack operations.
Example output:
error NU1101: Unable to find package Newtonsoft.Json.Extensions. No packages exist with this id in source(s): nuget.org
warning NU1603: Microsoft.EntityFrameworkCore 9.0.0 depends on Microsoft.Extensions.Caching.Memory (>= 9.0.0) but version Microsoft.Extensions.Caching.Memory 8.0.1 was resolved. Approve the package to suppress this warning.
error NU1605: Detected package downgrade: Microsoft.Extensions.Logging from 9.0.0 to 8.0.1. Reference the package directly from the project to select a different version.
Diagnosis:
Fix pattern:
<PackageReference> for the conflicting package at a compatible version, or use central package management to pin versions.Produced by Roslyn IDE analyzers for code style enforcement. These are usually warnings, not errors (unless .editorconfig escalates them).
Example output:
src/MyApp.Api/Program.cs(1,1): warning IDE0005: Using directive is unnecessary.
src/MyApp.Api/Models/Order.cs(8,12): warning IDE0044: Make field readonly
src/MyApp.Api/Services/Report.cs(22,5): warning IDE0058: Expression value is never used
Diagnosis:
using directive. Safe to remove.readonly because it is only assigned in the constructor._ = ... to explicitly discard.Fix pattern:
.editorconfig to promote warnings to errors for CI enforcement.Produced by the .NET code analysis SDK analyzers for API design, performance, reliability, and security rules.
Example output:
src/MyApp.Api/Services/CacheService.cs(34,9): warning CA1848: Use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])'. Using LoggerMessage delegates provides better performance.
src/MyApp.Api/Controllers/UserController.cs(12,5): warning CA2007: Consider calling ConfigureAwait on the awaited task
src/MyApp.Api/Crypto/HashService.cs(8,9): warning CA5351: Do Not Use Broken Cryptographic Algorithms (MD5)
Diagnosis:
[LoggerMessage] source generator attributes instead of string interpolation in log calls.ConfigureAwait(false) guidance for library code. Not applicable to ASP.NET Core app code (no SynchronizationContext).Fix pattern:
.editorconfig.NuGet restore is the first build step. When it fails, no compilation occurs. These are the most common restore failure patterns.
Example output:
Determining projects to restore...
Writing assets file to disk. Path: /src/MyApp.Api/obj/project.assets.json
/src/MyApp.Api/MyApp.Api.csproj : error NU1101: Unable to find package MyCompany.Shared.Models. No packages exist with this id in source(s): nuget.org
Failed to restore /src/MyApp.Api/MyApp.Api.csproj (in 2.14 sec).
Diagnosis:
nuget.config for feed configuration. NuGet searches feeds hierarchically upward from the project directory.packageSourceMapping configured? If so, the package must be mapped to a source that contains it. MyCompany.* patterns take precedence over * wildcard.Fix pattern:
# Check configured sources
dotnet nuget list source
# Check if nuget.config exists (searches upward from project dir)
ls nuget.config ../nuget.config ../../nuget.config 2>/dev/null
<!-- Add private feed to nuget.config -->
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="MyCompany" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="MyCompany">
<package pattern="MyCompany.*" />
</packageSource>
</packageSourceMapping>
</configuration>
Example output:
error NU1107: Version conflict detected for Microsoft.Extensions.DependencyInjection.Abstractions.
MyApp.Api -> Microsoft.EntityFrameworkCore 9.0.0 -> Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
MyApp.Api -> Microsoft.Extensions.Hosting 8.0.1 -> Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.1)
Diagnosis:
Fix pattern:
<!-- Upgrade the older top-level package to match -->
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<!-- Or add a direct reference to force a specific version -->
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
Example output:
Retrying 'FindPackagesByIdAsyncCore' for source 'https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json'.
Response status code does not indicate success: 401 (Unauthorized).
error NU1301: Unable to load the service index for source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json.
Diagnosis:
dotnet nuget update source with credentials or use Azure Artifacts Credential Provider.Fix pattern:
# Install Azure Artifacts Credential Provider (see official docs for platform-specific steps):
# https://github.com/microsoft/artifacts-credprovider#setup
# Windows: iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) }"
# macOS/Linux: sh -c "$(curl -fsSL https://aka.ms/install-artifacts-credprovider.sh)"
# Or add credentials explicitly to a specific source
dotnet nuget update source MyCompany --username az --password $PAT --store-password-in-clear-text
Analyzer warnings are produced by Roslyn analyzers bundled with the SDK or added via NuGet. Understanding when to fix vs. when to configure severity is critical.
src/MyApp.Api/Controllers/OrdersController.cs(27,5): warning CA2007: Consider calling ConfigureAwait on the awaited task [/src/MyApp.Api/MyApp.Api.csproj]
src/MyApp.Api/Services/OrderService.cs(15,16): warning CA1062: In externally visible method 'OrderService.Process(string)', validate parameter 'input' is non-null before using it [/src/MyApp.Api/MyApp.Api.csproj]
src/MyApp.Api/Models/UserDto.cs(8,12): warning IDE0032: Use auto-implemented property [/src/MyApp.Api/MyApp.Api.csproj]
Diagnosis:
CA = Code Analysis (.NET analyzers), IDE = IDE code style analyzers.<TreatWarningsAsErrors>true</TreatWarningsAsErrors> is set..editorconfig, or suppress with documented justification.Fix pattern:
ArgumentNullException.ThrowIfNull)..editorconfig when the rule doesn't apply project-wide (see below).| Severity | Build Impact | Action |
|---|---|---|
| Error | Build fails | Must fix before build succeeds |
| Warning | Build succeeds (unless <TreatWarningsAsErrors>true</TreatWarningsAsErrors>) | Fix or configure in .editorconfig |
| Suggestion | Build succeeds; shown in IDE | Fix when practical |
| Hidden | Not shown; available via code fix | Ignore unless actively refactoring |
Use .editorconfig to control analyzer behavior across the project:
# .editorconfig (place at solution root)
[*.cs]
# Promote nullable warnings to errors (recommended)
dotnet_diagnostic.CS8600.severity = error
dotnet_diagnostic.CS8602.severity = error
dotnet_diagnostic.CS8603.severity = error
# Suppress ConfigureAwait warning in ASP.NET Core apps (no SynchronizationContext)
dotnet_diagnostic.CA2007.severity = none
# Promote security warnings to errors
dotnet_diagnostic.CA5350.severity = error
dotnet_diagnostic.CA5351.severity = error
Suppression is acceptable ONLY when:
// ACCEPTABLE: documented justification
[SuppressMessage("Reliability", "CA2007:ConfigureAwait",
Justification = "ASP.NET Core has no SynchronizationContext")]
public async Task<Order> GetOrderAsync(int id, CancellationToken ct)
{
return await _repo.GetByIdAsync(id, ct);
}
// NOT ACCEPTABLE: no justification, hides a real issue
#pragma warning disable CA1062
public void Process(string input) { } // input could be null
#pragma warning restore CA1062
When a project targets multiple frameworks, MSBuild builds each TFM separately. Errors may appear for only one target.
MyApp.Shared -> /src/MyApp.Shared/bin/Debug/net8.0/MyApp.Shared.dll
src/MyApp.Shared/Services/FeatureService.cs(18,30): error CS1061: 'FrozenDictionary<string, int>' does not contain a definition for 'GetAlternateLookup' [/src/MyApp.Shared/MyApp.Shared.csproj -> net8.0]
MyApp.Shared -> /src/MyApp.Shared/bin/Debug/net9.0/MyApp.Shared.dll
Build succeeded for net9.0.
Build FAILED for net8.0.
Diagnosis:
[...csproj -> net8.0] shows which TFM failed. net9.0 succeeded.GetAlternateLookup was added in .NET 9. The code uses an API not available in .NET 8.Fix pattern:
// Use preprocessor directives for TFM-specific code
#if NET9_0_OR_GREATER
var lookup = frozenDict.GetAlternateLookup<ReadOnlySpan<char>>();
return lookup.TryGetValue(key, out var value) ? value : default;
#else
return frozenDict.TryGetValue(key.ToString(), out var value) ? value : default;
#endif
<!-- Or constrain the feature to specific TFMs in the project file -->
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<!-- TFM-conditional package reference -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
</ItemGroup>
Key patterns for identifying TFM-specific issues:
[ProjectPath -> TFM] suffix on every diagnostic line identifies the target.Build succeeded for netX.0 / Build FAILED for netX.0 summary at the end.Restored ... (net8.0, net9.0).bin/Debug/net8.0/ vs bin/Debug/net9.0/.The most frustrating build failures are ones that pass locally but fail in CI. These are almost always caused by environmental differences.
Example scenario:
Local: dotnet --version -> 9.0.200
CI: dotnet --version -> 9.0.100
Build error in CI:
error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*.
Diagnosis:
global.json file is either missing or not pinning the SDK version.Fix pattern:
// global.json -- pin SDK version for consistent builds
{
"sdk": {
"version": "9.0.200",
"rollForward": "latestPatch"
}
}
Example scenario:
CI error:
error NETSDK1147: To build this project, the following workloads must be installed: maui-android
Diagnosis:
Fix pattern:
# GitHub Actions example
- name: Install .NET workloads
run: dotnet workload install maui-android maui-ios
Example scenario:
Local restore succeeds (using cached packages).
CI error:
error NU1101: Unable to find package MyCompany.Internal.Lib.
Diagnosis:
nuget.config file is missing from the repository, or CI lacks feed credentials.Fix pattern:
nuget.config to the repository root with all required package sources.Example scenario:
Local (Windows): Build succeeds
CI (Linux): error MSB4018: The "ResolveAssemblyReference" task failed.
Could not find file '/src/MyApp/../Shared/MyLib.dll'
Diagnosis:
Fix pattern:
/) in .csproj paths -- MSBuild normalizes them on all platforms.docker run before pushing.Example scenario:
Local: Build succeeds with 3 warnings
CI: error CS8602: Dereference of a possibly null reference.
(because CI sets TreatWarningsAsErrors=true)
Diagnosis:
Directory.Build.props enables <TreatWarningsAsErrors>true</TreatWarningsAsErrors> via a CI-only condition.Fix pattern:
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> unconditionally in Directory.Build.props so local and CI builds behave identically.These patterns indicate an agent is hiding build problems rather than fixing them. Flag these during code review. See [skill:dotnet-slopwatch] for the automated quality gate that detects these patterns.
<!-- RED FLAG: blanket NoWarn in .csproj -->
<PropertyGroup>
<NoWarn>CS8600;CS8602;CS8603;CS8604;IL2026;IL2046</NoWarn>
</PropertyGroup>
// RED FLAG: pragma disable without justification
#pragma warning disable CS8618
public class UserModel
{
public string Name { get; set; } // non-nullable not initialized
public string Email { get; set; }
}
#pragma warning restore CS8618
Fix: Remove <NoWarn> entries and fix the underlying issues. If suppression is truly needed, use .editorconfig with per-rule severity and a comment explaining why.
// RED FLAG: suppressing security analyzer with no explanation
[SuppressMessage("Security", "CA5351")]
public byte[] HashData(byte[] input)
{
using var md5 = MD5.Create(); // insecure algorithm
return md5.ComputeHash(input);
}
# RED FLAG: disabling entire analyzer categories in .editorconfig
[*.cs]
dotnet_diagnostic.CA5350.severity = none
dotnet_diagnostic.CA5351.severity = none
dotnet_diagnostic.CA5358.severity = none
Fix: Replace insecure algorithms (MD5 -> SHA-256). If suppression is unavoidable (e.g., interop with a system requiring MD5), add a Justification string explaining the constraint.