Skip to content

artifacts-helper dotnet shim breaks C# Dev Kit Test Explorer #118

Description

@carlsonad-ksc

Summary

The artifacts-helper feature installs a dotnet shell-script wrapper at /usr/local/share/codespace-shims/dotnet and prepends that directory to PATH (via /etc/environment and a dotnet() bash function in ~/.bashrc).

This breaks the C# Dev Kit's Test Explorer in vscode. In the Test Explorer UI, the test projects' assemblies are listed but no tests appear under them, and attempting to run a test fails immediately with this message in the test window:

The test run did not record any output.

The "C# Dev Kit - Test Explorer" output channel shows a one-time initialization failure that cascades into every discovery/run operation:

[error] Initialization failed: Failed to find all versions of .NET Core MSBuild. Call to {0}. There may be more details in stderr.
[error] Test runner is not initialized. Call InitializeAsync first.

Environment

  • Base image: mcr.microsoft.com/devcontainers/dotnet:2-10.0-noble (Ubuntu 24.04, x64)
  • Feature: ghcr.io/microsoft/codespace-features/artifacts-helper:latest
  • .NET SDK 10.0.301, single SDK, installed at /usr/share/dotnet, no global.json
  • C# Dev Kit 3.20.199

Possible root cause

The Test Explorer appears to use MSBuild to discover and run tests. To locate the MSBuild it needs, it searches for the first dotnet executable on PATH, then uses the directory that dotnet sits in to find MSBuild relative to it (i.e. <dir>/host/fxr/... and <dir>/sdk/...).

When the artifacts-helper feature is installed in a dev container, its shim becomes the first dotnet on PATH — but the shim's parent directory (/usr/local/share/codespace-shims) does not contain the host/ and sdk/ directory structure that MSBuild is located under. So the relative lookup fails.

The ServiceHost log confirms this — it can't find the hostfxr library that lives under host/fxr:

Beginning to attempt to load unmanaged assembly 'hostfxr'.
Could not resolve 'hostfxr' using the AssemblyDependencyResolver.
Deferring to the default Core CLR policy of loading unmanaged assemblies.

Notably, the C# Dev Kit language server works fine (it honors DOTNET_ROOT/the existingDotnetPath setting), but the Test Explorer ServiceHost ignores DOTNET_ROOT for this resolution and keys off the dotnet location on PATH — so the shim is what surfaces the break.

The relative-search behavior, demonstrated

The .NET host resolves the SDK relative to its own directory — exactly what hostfxr_resolve_sdk2 does. With a real dotnet host and nothing beside it:

$ cp /usr/share/dotnet/dotnet /tmp/fakeroot/dotnet
$ /tmp/fakeroot/dotnet --list-sdks
Error: [/tmp/fakeroot/host/fxr] does not exist      # looks relative to its own dir

$ ln -s /usr/share/dotnet/{host,sdk,shared} /tmp/fakeroot/
$ /tmp/fakeroot/dotnet --list-sdks
10.0.301 [/tmp/fakeroot/sdk]                         # now resolves

Since the shim directory has neither host/ nor sdk/, any consumer that resolves the SDK relative to the dotnet it finds on PATH fails there.

Minimal reproduction

  1. Dev container from mcr.microsoft.com/devcontainers/dotnet:2-10.0-noble with the artifacts-helper feature enabled.
  2. Open a workspace with a .NET test project and the C# Dev Kit extension.
  3. Open the Test Explorer → projects appear but no tests; running a test reports "The test run did not record any output," and the log shows the error above.

Workaround (what we're using)

Set DOTNET_HOST_PATH (and DOTNET_ROOT) in devcontainer.json so resolution roots at the real install rather than the shim dir:

"remoteEnv": {
  "DOTNET_ROOT": "/usr/share/dotnet",
  "DOTNET_HOST_PATH": "/usr/share/dotnet/dotnet"
}

This is purely additive — it does not change PATH or disable the shim, so the feature's AzDO credential injection for terminal/CLI dotnet and nuget restores is unaffected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions