Summary
All 16 C# project files pin <Analyzer Include> paths to Meziantou.Analyzer.3.0.156 and
Roslynator.Analyzers.4.16.0, but every packages.config requests Meziantou.Analyzer 3.0.174 and
Roslynator.Analyzers 4.16.1. A restore therefore never produces the directories the projects
reference, and a build on a clean checkout fails with error CS0006: Metadata file '..\packages\Meziantou.Analyzer.3.0.156\analyzers\dotnet\roslyn5.0\cs\Meziantou.Analyzer.dll' could not be found (five such errors per project, 80 in total) before a single analyzer runs.
The skew was introduced by Dependabot commit f8e22af7 ("Bump the analyzers-dev-deps group with 2
updates"), which updated packages.config and the <Import>/<Error> lines to the new versions
but left the <Analyzer Include> item paths at the old ones. This is the known partial-update
failure mode of Dependabot against packages.config-style projects.
CI does not catch it, and the reason CI stays green is itself the more serious half of the defect.
.github/workflows/_build-analyzers.yml, _build-nullable.yml and _mstest-coverage.yml all cache
packages with key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }} and
restore-keys: nuget-${{ runner.os }}-. When packages.config changes, the exact key misses, the
prefix restore-key hits an older cache entry, and that older entry still contains the
Meziantou.Analyzer.3.0.156 and Roslynator.Analyzers.4.16.0 folders left over from before the
bump. The build resolves against those stale directories and succeeds.
Two consequences follow. First, CI's green result is an artifact of cache carry-over, not of a
correct build: any cache eviction or a change to runner.os reproduces the 80 CS0006 errors and
takes the entire pipeline red with no code change. Second, and continuously true today, the
analyzers actually executing in CI are the OLD versions (3.0.156 / 4.16.0) that the <Analyzer Include> items name, not the versions packages.config declares. Every analyzer-version bump in
this group has been silently inert since f8e22af7, so the repository's static-analysis gate is not
running the ruleset the dependency manifest claims.
Reproduced on 2026-08-26 in a clean worktree at commit c279d40b: nuget restore TaskMaster.sln
succeeded (172 packages), then msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true exited 1 with the
CS0006 errors above. Manually installing the two referenced older analyzer packages into
packages/ - which is exactly what CI's stale cache supplies - made the same command exit 0. That
substitution is the direct evidence for the cache-masking mechanism.
This defect is off the issue #614 defect chain and is filed separately rather than absorbed into it.
It was found while bootstrapping a clean worktree for #614; the #614 branch works around it locally
by installing the referenced analyzer versions into the gitignored packages/ directory, and
changes no project file.
Likely fix: update the <Analyzer Include> paths in all 16 .csproj files to match
packages.config, then remediate whatever diagnostics the newer analyzers surface. Separately,
remove the restore-keys prefix fallback (or scope it so it cannot serve a cache built from a
different packages.config) so a partial dependency update fails CI instead of being masked. The
project-file repair and the workflow repair should be scoped and validated together, because the
first will expose analyzer diagnostics that the second must not re-hide.
Environment
- OS/version: Windows 11 Pro 10.0.26200; Visual Studio 18 Community MSBuild 18.8.2; NuGet CLI latest.
- Python version: Not applicable; this is a C# / MSBuild build-configuration defect.
- Command/flags used:
nuget restore TaskMaster.sln then
msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true
- Data source or fixture: Clean git worktree at commit
c279d40b with no pre-existing packages/
directory.
Steps to Reproduce
- Create a clean checkout or worktree with no
packages/ directory present.
- Run
nuget restore TaskMaster.sln. It succeeds and installs Meziantou.Analyzer.3.0.174 and
Roslynator.Analyzers.4.16.1.
- Run the analyzer build command above.
- Observe
error CS0006 for Meziantou.Analyzer.3.0.156 and Roslynator.Analyzers.4.16.0 on every
C# project, and a non-zero exit code.
Expected Behavior
A clean checkout restores exactly the analyzer packages the projects reference, and the analyzer
build succeeds. The analyzer versions that execute are the versions packages.config declares. CI
fails when a dependency update leaves project files inconsistent with packages.config.
Actual Behavior
A clean checkout fails the analyzer build with 80 CS0006 errors. CI passes only because a
prefix restore-keys cache hit supplies analyzer directories left over from before the version
bump, so CI silently runs the superseded analyzer versions.
CSC : error CS0006: Metadata file '..\packages\Meziantou.Analyzer.3.0.156\analyzers\dotnet\roslyn5.0\cs\Meziantou.Analyzer.dll' could not be found [UtilitiesCS\UtilitiesCS.csproj]
CSC : error CS0006: Metadata file '..\packages\Roslynator.Analyzers.4.16.0\analyzers\dotnet\roslyn4.7\cs\Roslynator.CSharp.Analyzers.dll' could not be found [UtilitiesCS\UtilitiesCS.csproj]
Logs / Screenshots
Impact / Severity
The static-analysis gate is running versions other than the declared ones, and the pipeline is one
cache eviction away from going red across every job with no code change.
Source
From: docs/features/potential/2026-08-26-analyzer-include-paths-skewed-from-packages-config-masked-by-ci-cache.md
Summary
All 16 C# project files pin
<Analyzer Include>paths toMeziantou.Analyzer.3.0.156andRoslynator.Analyzers.4.16.0, but everypackages.configrequestsMeziantou.Analyzer 3.0.174andRoslynator.Analyzers 4.16.1. A restore therefore never produces the directories the projectsreference, and a build on a clean checkout fails with
error CS0006: Metadata file '..\packages\Meziantou.Analyzer.3.0.156\analyzers\dotnet\roslyn5.0\cs\Meziantou.Analyzer.dll' could not be found(five such errors per project, 80 in total) before a single analyzer runs.The skew was introduced by Dependabot commit
f8e22af7("Bump the analyzers-dev-deps group with 2updates"), which updated
packages.configand the<Import>/<Error>lines to the new versionsbut left the
<Analyzer Include>item paths at the old ones. This is the known partial-updatefailure mode of Dependabot against
packages.config-style projects.CI does not catch it, and the reason CI stays green is itself the more serious half of the defect.
.github/workflows/_build-analyzers.yml,_build-nullable.ymland_mstest-coverage.ymlall cachepackageswithkey: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}andrestore-keys: nuget-${{ runner.os }}-. Whenpackages.configchanges, the exact key misses, theprefix restore-key hits an older cache entry, and that older entry still contains the
Meziantou.Analyzer.3.0.156andRoslynator.Analyzers.4.16.0folders left over from before thebump. The build resolves against those stale directories and succeeds.
Two consequences follow. First, CI's green result is an artifact of cache carry-over, not of a
correct build: any cache eviction or a change to
runner.osreproduces the 80CS0006errors andtakes the entire pipeline red with no code change. Second, and continuously true today, the
analyzers actually executing in CI are the OLD versions (3.0.156 / 4.16.0) that the
<Analyzer Include>items name, not the versionspackages.configdeclares. Every analyzer-version bump inthis group has been silently inert since
f8e22af7, so the repository's static-analysis gate is notrunning the ruleset the dependency manifest claims.
Reproduced on 2026-08-26 in a clean worktree at commit
c279d40b:nuget restore TaskMaster.slnsucceeded (172 packages), then
msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=trueexited 1 with theCS0006errors above. Manually installing the two referenced older analyzer packages intopackages/- which is exactly what CI's stale cache supplies - made the same command exit 0. Thatsubstitution is the direct evidence for the cache-masking mechanism.
This defect is off the issue #614 defect chain and is filed separately rather than absorbed into it.
It was found while bootstrapping a clean worktree for #614; the #614 branch works around it locally
by installing the referenced analyzer versions into the gitignored
packages/directory, andchanges no project file.
Likely fix: update the
<Analyzer Include>paths in all 16.csprojfiles to matchpackages.config, then remediate whatever diagnostics the newer analyzers surface. Separately,remove the
restore-keysprefix fallback (or scope it so it cannot serve a cache built from adifferent
packages.config) so a partial dependency update fails CI instead of being masked. Theproject-file repair and the workflow repair should be scoped and validated together, because the
first will expose analyzer diagnostics that the second must not re-hide.
Environment
nuget restore TaskMaster.slnthenmsbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=truec279d40bwith no pre-existingpackages/directory.
Steps to Reproduce
packages/directory present.nuget restore TaskMaster.sln. It succeeds and installsMeziantou.Analyzer.3.0.174andRoslynator.Analyzers.4.16.1.error CS0006forMeziantou.Analyzer.3.0.156andRoslynator.Analyzers.4.16.0on everyC# project, and a non-zero exit code.
Expected Behavior
A clean checkout restores exactly the analyzer packages the projects reference, and the analyzer
build succeeds. The analyzer versions that execute are the versions
packages.configdeclares. CIfails when a dependency update leaves project files inconsistent with
packages.config.Actual Behavior
A clean checkout fails the analyzer build with 80
CS0006errors. CI passes only because aprefix
restore-keyscache hit supplies analyzer directories left over from before the versionbump, so CI silently runs the superseded analyzer versions.
Logs / Screenshots
CS0006errors above, captured from the failingmsbuild /t:Rebuildrun.Impact / Severity
The static-analysis gate is running versions other than the declared ones, and the pipeline is one
cache eviction away from going red across every job with no code change.
Source
From: docs/features/potential/2026-08-26-analyzer-include-paths-skewed-from-packages-config-masked-by-ci-cache.md