CSProj Duplicate PackageReference Trap
Definition
When git auto-merges or rebases produce a .csproj with two or more <PackageReference> lines for the same package, MSBuild builds opaquely without flagging the dup. Downstream behaviour is undefined: usually the first reference wins, sometimes a NuGet downgrade warning fires, sometimes a transitive dependency resolves to an unexpected version. Restore appears to succeed; build fails far away from the actual cause.
How it shows up
Most-frequent offender in CRMAPIGenerator: Newtonsoft.Json in Templates/Templates.csproj. Runs on Builder agent fail with errors like:
CS0246: The type or namespace name 'JsonConvert' could not be foundMSB3277: Found conflicts between different versions of "Newtonsoft.Json"- Or worse: build succeeds but the runtime throws
MissingMethodExceptionagainst a method that exists in a different version
How to fix
# Find duplicates in any csproj:
grep -nE 'PackageReference Include="([^"]+)"' Templates/Templates.csproj | sort -u | wc -l
# Compare to total PackageReference lines:
grep -cE 'PackageReference Include="' Templates/Templates.csproj
# If counts differ, you have duplicates.Manual fix: open the csproj, dedupe the <PackageReference> lines, keep the highest version, run dotnet restore && dotnet build.
Why agents miss it
Builder agent gets a dotnet build failure stderr, doesn’t grep for duplicate refs in the csproj, and tries to “fix” the surface error (e.g. adds an <Import> it doesn’t need). This compounds the problem.
Prescription for the Builder agent
When dotnet build fails AND the diff for this run touched any .csproj, before any other action:
grep -E 'PackageReference Include="([^"]+)"' <touched-csproj>and check for duplicates- If duplicates exist, dedupe (keep highest version) and retry
- If still failing, then proceed to other diagnostics
Related
[[NuGet-v3-vs-v6-Resolution]]— adjacent: not about duplicates but about transitive resolution- `CRMAPIGenerator-Repository — the project where this trap lives