Skip to content

Bug: csproj-analyzer-paths-stale-after-dependabot-bump-breaks-fresh-clone #597

Closed

Description

@drmoisan
  • Work Mode: full-bug

Summary

packages.config pins Meziantou.Analyzer 3.0.174 and Roslynator.Analyzers 4.16.1, but 80 unconditional <Analyzer Include> items across 16 first-party .csproj files still point at the previous 3.0.156 / 4.16.0 package folders. A clean checkout restores only the pinned versions, so those 80 analyzer paths do not exist and the build fails with error CS0006. A fresh clone of main cannot build. CI passes only because its NuGet cache has a prefix restore-keys fallback that restores a pre-bump packages tree.

Environment

  • OS/version: Windows 11 Pro 10.0.26200
  • Python version: n/a - C# / MSBuild
  • Command/flags used: msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true
  • Data source or fixture: main at d15f9510; introduced by PR Bump the analyzers-dev-deps group with 2 updates #573 (merged eb6f6836)

Steps to Reproduce

  1. Clone the repository into a directory with no pre-existing packages/ folder, or delete packages/ entirely.
  2. Run nuget restore TaskMaster.sln. Only Meziantou.Analyzer.3.0.174 and Roslynator.Analyzers.4.16.1 are installed, because those are what packages.config pins.
  3. Run the analyzer build command above.
  4. Observe the failure.
  5. For the CI side, inspect .github/workflows/_build-analyzers.yml and note the cache restore-keys prefix fallback.

Expected Behavior

A clean checkout restores the pinned analyzer packages and builds. <Analyzer Include> paths agree with the versions packages.config pins.

Actual Behavior

The 80 stale <Analyzer Include> paths reference package folders that a clean restore never creates, so MSBuild reports error CS0006 (metadata file not found) and exits 1.

Counted over tracked first-party project files only (git ls-files '*.csproj', 18 files):

Meziantou 3.0.156 lines : 16
Roslynator 4.16.0 lines : 64
TOTAL stale lines       : 80  across 16 files
lines citing 3.0.174 / 4.16.1 : 0

The items carry no Condition attribute, so they are evaluated unconditionally and a missing file is fatal rather than skipped. PR #573 was a Dependabot group bump that correctly updated packages.config and the Condition-guarded Import / Error lines, but not these hand-authored items - they were added by issue #181 and sit under the comment <!-- Issue #181: analyzer-only references (first-party scope). -->.

Why nothing caught it. Two independent maskings:

  1. Local verification. The analyzer, nullable, and MSTest gates were run against PR Bump the analyzers-dev-deps group with 2 updates #573 and were green. They were green because a long-lived packages/ directory holds Meziantou.Analyzer.3.0.101, 3.0.123, 3.0.156, 3.0.174, Roslynator.Analyzers.4.16.0, and 4.16.1 from historical restores, so the stale paths resolve. A clean environment has only the two pinned versions.
  2. CI. .github/workflows/_build-analyzers.yml uses key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }} with restore-keys: nuget-${{ runner.os }}-. When the content-hash key misses - which is exactly what a packages.config bump causes - the prefix fallback restores an older cache containing the pre-bump packages, and the stale paths resolve. Green CI on a packages.config change is therefore not evidence that a clean restore builds.

Logs / Screenshots

  • Attached minimal logs or screenshot

  • Snippet - the offending shape, QuickFiler/QuickFiler.csproj:581-586:

    <!-- Issue #181: analyzer-only references (first-party scope). Severities are set to suggestion in .editorconfig so none break the nullable TreatWarningsAsErrors build. -->
    <Analyzer Include="..\packages\Meziantou.Analyzer.3.0.156\analyzers\dotnet\roslyn5.0\cs\Meziantou.Analyzer.dll" />
    <Analyzer Include="..\packages\Roslynator.Analyzers.4.16.0\analyzers\dotnet\roslyn4.7\cs\Roslynator.CSharp.Analyzers.dll" />
    <Analyzer Include="..\packages\Roslynator.Analyzers.4.16.0\analyzers\dotnet\roslyn4.7\cs\Roslynator_Analyzers_Roslynator.Common.dll" />
    <Analyzer Include="..\packages\Roslynator.Analyzers.4.16.0\analyzers\dotnet\roslyn4.7\cs\Roslynator_Analyzers_Roslynator.Core.dll" />
    <Analyzer Include="..\packages\Roslynator.Analyzers.4.16.0\analyzers\dotnet\roslyn4.7\cs\Roslynator_Analyzers_Roslynator.CSharp.dll" />

Impact / Severity

  • Blocker
  • High
  • Medium
  • Low

Blocker for onboarding and for any clean-environment build: a new clone, a fresh CI runner with a cold cache, or a developer who clears packages/ all hit error CS0006. It is not a blocker for the current working tree or for CI as presently configured, which is precisely why it has gone unnoticed since PR #573 merged. The severity reflects that the masking is incidental and can evaporate at any time - a cache eviction is enough.

Source

From: docs/features/potential/2026-08-23-csproj-analyzer-paths-stale-after-dependabot-bump-breaks-fresh-clone.md

Activity

  1. drmoisan commented on Sep 2, 2026

    @drmoisan
    OwnerAuthor

    Closing as completed. Delivered via PR #703 (commit ece554d3, "(chore): update project references"), an ancestor of origin/main.

    Confirmed directly against origin/main: every first-party packages.config pins Meziantou.Analyzer 3.0.194 and Roslynator.Analyzers 5.0.0, and a repo-wide scan of the hand-authored <Analyzer Include> items across all 16 .csproj files that carry them shows exactly 16 lines citing 3.0.194 (Meziantou) and 64 lines citing 5.0.0 (Roslynator) — 80 lines total, zero lines citing any stale version. This is the same 16-file/80-line population the issue counted, now fully in sync rather than pointing at package folders a clean restore never creates.

    History confirms the drift and its resolution: commit f8e22af7 (dependabot bump 3.0.156→3.0.174) updated only the NuGet-managed Import/Error guard lines, leaving the hand-authored <Analyzer Include> items stuck at 3.0.156/4.16.0 through several subsequent commits (matching the issue's exact snapshot at d15f9510). Commit ece554d3 brought the hand-authored items back into sync with packages.config (at that point 3.0.194/5.0.0), eliminating the CS0006-on-clean-clone failure mode described in the issue.

    Verified during a full-repo bug sweep (2026-09-02). No branch or PR remains to ship; this was left open only as bookkeeping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions