Skip to content

Fix dotnet tool restore misattributing commands between packages when DOTNET_CLI_HOME points to a fresh directory#53866

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/fix-dotnet-tool-restore-issue
Draft

Fix dotnet tool restore misattributing commands between packages when DOTNET_CLI_HOME points to a fresh directory#53866
Copilot wants to merge 2 commits intomainfrom
copilot/fix-dotnet-tool-restore-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 14, 2026

dotnet tool restore fails on first run with a fresh DOTNET_CLI_HOME when the manifest contains 2+ tools, reporting that the second tool's command belongs to the first tool's package.

Root Cause

ToolPackageDownloaderBase creates a single shared _localToolAssetDir (temp directory) reused across all package installations in one restore operation. When the first tool uses a RID-specific package (e.g. dotnet-ef), DownloadTool writes both project.assets.json and project.assets.ridpackage.json to that directory. When the second tool doesn't need a RID-specific package, only project.assets.json is overwritten — the stale project.assets.ridpackage.json remains.

ToolPackageInstance for the second tool finds the stale project.assets.ridpackage.json and reads it preferentially, returning the first tool's command name. The manifest validation then fails:

The command "dotnet-outdated" specified in the tool manifest file is not contained in the package
with Package Id dotnet-outdated-tool. The commands contained in the package are dotnet-ef.

This only manifests on a cold cache because on warm cache runs, PackageHasBeenRestored short-circuits the first tool's re-installation, so no stale file is created.

Changes

  • ToolPackageDownloaderBase.DownloadTool — delete any existing project.assets.ridpackage.json from the shared asset directory after writing the main project.assets.json and before calling ResolveRidSpecificPackage, so each tool starts with a clean slate
  • ToolPackageDownloaderBase.TryGetDownloadedTool — same cleanup for the same reason
  • ToolPackageDownloaderTests — regression test that pre-plants a stale project.assets.ridpackage.json in _localToolAssetDir, installs a local tool, and asserts the stale file is removed and the correct command is returned

…is set to fresh directory

Root cause: ToolPackageDownloaderBase uses a shared _localToolAssetDir for all package
installations. When the first tool uses a RID-specific package, it creates
project.assets.ridpackage.json in this shared directory. When the second tool
doesn't need a RID-specific package, this file is not overwritten, causing
ToolPackageInstance to read the wrong assets file and misattribute the first
tool's command to the second tool.

Fix: Delete any stale project.assets.ridpackage.json before checking if the
current package needs a RID-specific package, in both DownloadTool and
TryGetDownloadedTool. Add a regression test that verifies the stale file is
cleaned up and the correct command is returned.

Agent-Logs-Url: https://github.com/dotnet/sdk/sessions/5147c8a9-8386-43f4-8c86-3b65fc3c55f0

Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix dotnet tool restore command misattribution with custom DOTNET_CLI_HOME Fix dotnet tool restore misattributing commands between packages when DOTNET_CLI_HOME points to a fresh directory Apr 14, 2026
Copilot AI requested a review from marcpopMSFT April 14, 2026 20:35
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.

dotnet tool restore misattributes commands between packages when DOTNET_CLI_HOME is set to a fresh directory

2 participants