Skip to content

Use SpecialFolderOption.DoNotVerify in GetFolderPath to avoid empty path on Linux#54510

Closed
Copilot wants to merge 5 commits into
mainfrom
copilot/fix-getfolderpath-empty-string
Closed

Use SpecialFolderOption.DoNotVerify in GetFolderPath to avoid empty path on Linux#54510
Copilot wants to merge 5 commits into
mainfrom
copilot/fix-getfolderpath-empty-string

Conversation

Copilot AI commented May 29, 2026

Copy link
Copy Markdown
Contributor

Environment.GetFolderPath(SpecialFolder.LocalApplicationData) returns an empty string on Linux when ~/.local/share doesn't exist (documented BCL behavior). Two locations in the SDK treat this as a fatal error, breaking functionality on minimal Linux environments (e.g., bare GitHub Ubuntu runners).

Changes

  • DotnetupPaths.GetBaseDirectory() (primary fix): Switch to the two-argument overload with SpecialFolderOption.DoNotVerify, so the path is computed regardless of whether the directory exists yet — preventing dotnetup from throwing InvalidOperationException on bare Linux environments. Directory creation is handled later by the existing EnsureDataDirectoryExists call.

  • VirtualProjectBuilder.GetTempSubdirectory(): Same fix applied — ensures dotnet run <file> does not fail on Linux when ~/.local/share is absent.

  • VirtualProjectBuilderTests (new): Added a regression test (GetTempSubdirectory_ReturnsNonEmptyPath_WhenXdgDataHomeDoesNotExist) that sets XDG_DATA_HOME to a non-existent directory and verifies GetTempSubdirectory() returns a valid, non-empty path rooted under it. The test is gated to Linux/FreeBSD via [PlatformSpecificFact(TestPlatforms.Linux | TestPlatforms.FreeBSD)].

…th on Linux

Co-authored-by: nagilson <23152278+nagilson@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix BCL GetFolderPath APIs returning empty paths Use SpecialFolderOption.Create in GetTempSubdirectory to avoid empty path on Linux May 29, 2026
Copilot AI requested a review from nagilson May 29, 2026 19:03
@nagilson

nagilson commented May 29, 2026

Copy link
Copy Markdown
Member

@copilot is there a good way to add a test that checks this scenario (e.g. overriding environment variables based on the runtime implementation, launching the dotnetup e2e process) - since there is no file system mock? I'd like to be able to prevent regression here.

Co-authored-by: nagilson <23152278+nagilson@users.noreply.github.com>

Copilot AI commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot is there a good way to add a test that checks this scenario (e.g. overriding environment variables based on the runtime implementation, launching the dotnetup e2e process) - since there is n...

Yes — since VirtualProjectBuilder internals are visible to dotnet.Tests, we can write a unit test that manipulates XDG_DATA_HOME directly in-process (the BCL's GetFolderPath reads it from the environment at call time).

I added VirtualProjectBuilderTests.GetTempSubdirectory_ReturnsNonEmptyPath_WhenXdgDataHomeDoesNotExist in test/dotnet.Tests/ProjectTools/VirtualProjectBuilderTests.cs (commit in this PR). The test:

  1. Points XDG_DATA_HOME at a unique temp path that doesn't exist yet.
  2. Calls VirtualProjectBuilder.GetTempSubdirectory().
  3. Asserts the result is non-empty and is rooted under the new XDG_DATA_HOME (confirming SpecialFolderOption.Create created it).
  4. Restores XDG_DATA_HOME and cleans up in a finally block.

It's gated to Linux/FreeBSD (where XDG_DATA_HOME / ~/.local/share is the fallback) via [PlatformSpecificFact(TestPlatforms.Linux | TestPlatforms.FreeBSD)].

@baronfel

Copy link
Copy Markdown
Member

@copilot I think this is the wrong location - the linked issue is about the use of this method in dotnetup, not the dotnet CLI primarily.

@nagilson

Copy link
Copy Markdown
Member

@copilot you need to use release/dnup as a base branch and make a PR into there, not main.

string directory = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Path.GetTempPath()
: Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
: Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.Create);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use SpecialFolderOption.DoNotVerify instead of SpecialFolderOption.Create, so that the path is computed regardless of whether it exists yet. dotnetup creates it later via EnsureDataDirectoryExists.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — switched to SpecialFolderOption.DoNotVerify in both VirtualProjectBuilder.GetTempSubdirectory() and DotnetupPaths.GetBaseDirectory(). The directory creation is left to the existing EnsureDataDirectoryExists call. Commit: Use SpecialFolderOption.DoNotVerify instead of Create in GetFolderPath calls.

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>

Copilot AI commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot I think this is the wrong location - the linked issue is about the use of this method in dotnetup, not the dotnet CLI primarily.

Fixed in the latest commit. DotnetupPaths.GetBaseDirectory() now uses SpecialFolderOption.Create so dotnetup no longer receives an empty path on bare Linux environments. The VirtualProjectBuilder fix is kept as well since it had the identical bug.

Copilot AI changed the title Use SpecialFolderOption.Create in GetTempSubdirectory to avoid empty path on Linux Use SpecialFolderOption.Create in GetFolderPath to avoid empty path on Linux May 29, 2026
Copilot AI requested a review from baronfel May 29, 2026 20:29
…h calls

Co-authored-by: nagilson <36081148+nagilson@users.noreply.github.com>

Copilot AI commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot you need to use release/dnup as a base branch and make a PR into there, not main.

Noted — I'm not able to retarget the PR's base branch directly. Please retarget this PR to release/dnup manually via the GitHub UI (Edit → Base), or close and re-open against release/dnup.

Copilot AI changed the title Use SpecialFolderOption.Create in GetFolderPath to avoid empty path on Linux Use SpecialFolderOption.DoNotVerify in GetFolderPath to avoid empty path on Linux May 29, 2026
Copilot AI requested a review from lbussell May 29, 2026 20:39
@lbussell lbussell closed this May 29, 2026
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.

BCL GetFolderPath APIs may return empty paths, which dotnetup interprets as an error

4 participants