Summary
The three build and test workflows restore the packages directory from an
actions/cache entry whose restore-keys fallback is a bare
nuget-${{ runner.os }}- prefix. On a cache miss the fallback supplies package
folders from an unrelated earlier commit, so a project referencing a package
version that packages.config no longer declares still compiles. Two real
defects on PR #568 were invisible to CI for exactly this reason and only
appeared on a local cold build.
Environment
- OS/version:
windows-latest GitHub-hosted runner
- Python version: n/a (GitHub Actions YAML)
- Command/flags used:
nuget restore TaskMaster.sln, then the workflow's msbuild or vstest step
- Data source or fixture:
actions/cache@v4 entry keyed on **/packages.config
Steps to Reproduce
- On a branch, change a package version in every
packages.config but leave a
stale ..\packages\<Id>.<OldVersion>\ path in a .csproj or in test code.
- Push. The cache key
nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}
misses because the config files changed.
- The
restore-keys: nuget-${{ runner.os }}- fallback restores a prior cache
that still contains <Id>.<OldVersion>.
nuget restore installs the new versions alongside the stale restored ones.
- The build and the tests pass, despite referencing a version no longer
declared anywhere in the repository.
Expected Behavior
CI reflects what a clean checkout produces. A project or test that references a
package version absent from packages.config fails the build, because that is
what any developer with a cold packages directory experiences.
Actual Behavior
CI run 31890892701 on chore/update-nuget head 8f30fd53 reported
build-analyzers, build-nullable, and mstest-coverage as success. The
same commit built locally against a correctly-restored packages directory
produced:
- 10
CSC : error CS0006: Metadata file '..\packages\Meziantou.Analyzer.3.0.138\...' could not be found errors (and the matching Roslynator.Analyzers.4.15.0
errors) across 16 projects, because the upgrade advanced packages.config and
the analyzer <Import>/<Error> lines to 3.0.156 / 4.16.0 but left the
<Analyzer Include> item paths behind.
- 3 test failures in
UtilitiesCS.Test.Extensions.AsyncSerialization_Tests
(InvalidOperationException: The Microsoft.Graph.xml fixture could not be located from the test assembly path), because the fixture hard-coded
packages\Microsoft.Graph.6.2.0 while the upgrade moved to 6.5.0.
Only the format-check job failed, and it is the one job with no packages
cache dependency.
Logs / Screenshots
Impact / Severity
High because it is a gate-fidelity defect, not an ordinary bug: it caused three
protected checks to report green on a commit that does not build from a clean
checkout. Any future package-path drift is silently admitted to main the same
way. It also affects the correctness signal of every prior green run whose cache
was populated from an older commit.
Source
From: docs/features/potential/2026-08-15-ci-nuget-cache-fallback-masks-stale-package-refs.md
Summary
The three build and test workflows restore the
packagesdirectory from anactions/cacheentry whoserestore-keysfallback is a barenuget-${{ runner.os }}-prefix. On a cache miss the fallback supplies packagefolders from an unrelated earlier commit, so a project referencing a package
version that
packages.configno longer declares still compiles. Two realdefects on PR #568 were invisible to CI for exactly this reason and only
appeared on a local cold build.
Environment
windows-latestGitHub-hosted runnernuget restore TaskMaster.sln, then the workflow's msbuild or vstest stepactions/cache@v4entry keyed on**/packages.configSteps to Reproduce
packages.configbut leave astale
..\packages\<Id>.<OldVersion>\path in a.csprojor in test code.nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}misses because the config files changed.
restore-keys: nuget-${{ runner.os }}-fallback restores a prior cachethat still contains
<Id>.<OldVersion>.nuget restoreinstalls the new versions alongside the stale restored ones.declared anywhere in the repository.
Expected Behavior
CI reflects what a clean checkout produces. A project or test that references a
package version absent from
packages.configfails the build, because that iswhat any developer with a cold
packagesdirectory experiences.Actual Behavior
CI run 31890892701 on
chore/update-nugethead8f30fd53reportedbuild-analyzers,build-nullable, andmstest-coverageas success. Thesame commit built locally against a correctly-restored
packagesdirectoryproduced:
CSC : error CS0006: Metadata file '..\packages\Meziantou.Analyzer.3.0.138\...' could not be founderrors (and the matchingRoslynator.Analyzers.4.15.0errors) across 16 projects, because the upgrade advanced
packages.configandthe analyzer
<Import>/<Error>lines to 3.0.156 / 4.16.0 but left the<Analyzer Include>item paths behind.UtilitiesCS.Test.Extensions.AsyncSerialization_Tests(
InvalidOperationException: The Microsoft.Graph.xml fixture could not be located from the test assembly path), because the fixture hard-codedpackages\Microsoft.Graph.6.2.0while the upgrade moved to 6.5.0.Only the
format-checkjob failed, and it is the one job with nopackagescache dependency.
Logs / Screenshots
commit that fails a cold local build; local msbuild CS0006 output and the TRX
failure messages quoted above. Both defects were fixed in commit
46ca9210.Impact / Severity
High because it is a gate-fidelity defect, not an ordinary bug: it caused three
protected checks to report green on a commit that does not build from a clean
checkout. Any future package-path drift is silently admitted to
mainthe sameway. It also affects the correctness signal of every prior green run whose cache
was populated from an older commit.
Source
From: docs/features/potential/2026-08-15-ci-nuget-cache-fallback-masks-stale-package-refs.md