Skip to content

Pin .NET SDK to 10.0.204 via global.json#962

Merged
erikdarlingdata merged 1 commit into
devfrom
feature/pin-net-sdk-via-globaljson
May 19, 2026
Merged

Pin .NET SDK to 10.0.204 via global.json#962
erikdarlingdata merged 1 commit into
devfrom
feature/pin-net-sdk-via-globaljson

Conversation

@erikdarlingdata
Copy link
Copy Markdown
Owner

Summary

Today's nightly build failed restoring `Installer/PerformanceMonitorInstaller.csproj` with:

```
error NU1004: The package reference Microsoft.NET.ILLink.Tasks
version has changed from [10.0.8, ) to [10.0.7, ).
The packages lock file is inconsistent with the project dependencies
so restore can't be run in locked mode.
```

`Microsoft.NET.ILLink.Tasks` is bundled with the .NET SDK, so its version is whatever SDK the GitHub runner image happens to ship. The lockfiles were generated against SDK 10.0.204 (runtime 10.0.8); the runner now ships SDK 10.0.107 (runtime 10.0.7), and `dotnet restore --locked-mode` correctly refused to silently rewrite the lock.

Fix

A `global.json` at the repo root pins the SDK:

```json
{
"sdk": {
"version": "10.0.204",
"rollForward": "latestFeature",
"allowPrerelease": false
}
}
```

`actions/setup-dotnet` reads `global.json` automatically and downloads SDK 10.0.204 (or higher within 10.0.x) on the runner if it isn't already present, regardless of what the runner image ships with. Local dev and CI now agree on the SDK, and the only way to bump it is to edit `global.json` and regenerate lockfiles in the same commit — failures will surface in PR CI, not as a 4am nightly surprise.

Test

```text
$ dotnet --version
10.0.204

$ dotnet restore Installer/PerformanceMonitorInstaller.csproj --locked-mode
Determining projects to restore...
Restored .../Installer/PerformanceMonitorInstaller.csproj (in 476 ms).
Restored .../Installer.Core/Installer.Core.csproj (in 476 ms).
```

What's deliberately not in this PR

  • `nightly.yml` on `main` still has the pre-.NET-10 `Setup .NET 8.0` step (`dotnet-version: 8.0.x`). dev's copy was already updated to `10.0.x` during the .NET 10 upgrade, so the next `dev → main` release sweeps that up automatically. No separate fix needed here.
  • Lockfiles are not regenerated. With `global.json` in place, the existing 10.0.8-pinned lockfiles are correct.

🤖 Generated with Claude Code

Today's nightly build on main failed restoring Installer with NU1004:
'Microsoft.NET.ILLink.Tasks version has changed from [10.0.8, ) to
[10.0.7, )'. ILLink.Tasks is bundled with the SDK, so its version
tracks whatever SDK the runner image happens to ship. The lockfiles
were generated against SDK 10.0.204 (runtime 10.0.8); the runner now
ships SDK 10.0.107 (runtime 10.0.7), and `--locked-mode` refuses to
proceed against the mismatch.

global.json tells the SDK host (and actions/setup-dotnet) to use 10.0.204
or higher within the same major.minor — so CI installs the SDK that
matches the lockfile instead of inheriting whatever the runner image
came with. Local dev and CI now agree on the SDK version, and the only
way to bump it is to update global.json and regenerate lockfiles in the
same commit.

Verified locally: `dotnet --version` → 10.0.204, `dotnet restore
--locked-mode` succeeds.

Note: dev's nightly.yml is already on 10.0.x. main's still has the
.NET 8.0 leftover but that'll clear on the next dev → main release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@erikdarlingdata erikdarlingdata merged commit 782e2bf into dev May 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant