Fix dotnet tool restore misattributing commands between packages when DOTNET_CLI_HOME points to a fresh directory#53866
Draft
Fix dotnet tool restore misattributing commands between packages when DOTNET_CLI_HOME points to a fresh directory#53866
Conversation
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
dotnet tool restorefails on first run with a freshDOTNET_CLI_HOMEwhen the manifest contains 2+ tools, reporting that the second tool's command belongs to the first tool's package.Root Cause
ToolPackageDownloaderBasecreates 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),DownloadToolwrites bothproject.assets.jsonandproject.assets.ridpackage.jsonto that directory. When the second tool doesn't need a RID-specific package, onlyproject.assets.jsonis overwritten — the staleproject.assets.ridpackage.jsonremains.ToolPackageInstancefor the second tool finds the staleproject.assets.ridpackage.jsonand reads it preferentially, returning the first tool's command name. The manifest validation then fails:This only manifests on a cold cache because on warm cache runs,
PackageHasBeenRestoredshort-circuits the first tool's re-installation, so no stale file is created.Changes
ToolPackageDownloaderBase.DownloadTool— delete any existingproject.assets.ridpackage.jsonfrom the shared asset directory after writing the mainproject.assets.jsonand before callingResolveRidSpecificPackage, so each tool starts with a clean slateToolPackageDownloaderBase.TryGetDownloadedTool— same cleanup for the same reasonToolPackageDownloaderTests— regression test that pre-plants a staleproject.assets.ridpackage.jsonin_localToolAssetDir, installs a local tool, and asserts the stale file is removed and the correct command is returned