Skip to content

Language server path not passed to dotnet command, dotnet.server.path setting ignored #8895

@d-b-c-e

Description

@d-b-c-e

[BUG] Language server path not passed to dotnet command, dotnet.server.path setting ignored

Environment

  • OS: SteamOS 3.7.19 (Arch-based, Steam Deck)
  • VS Code Version: Native tarball install (not Flatpak)
  • C# Extension Version: [email protected]
  • dotnet-runtime Extension Version: [email protected]
  • .NET SDK Version: 9.0.309 (installed at ~/.dotnet/)

Bug Summary

The C# extension fails to start the Roslyn language server due to three related bugs:

  1. Missing server path: The extension invokes dotnet without passing the language server executable path
  2. dotnet.server.path ignored: This documented setting has no effect
  3. Inconsistent dotnet resolution: The extension uses dotnet.dotnetPath for some operations but PATH for the language server spawn

Actual Behavior

When the extension activates, it runs:

dotnet --logLevel Information --telemetryLevel all --extensionLogDirectory /path/to/logs

This fails with:

Could not execute because the specified command or file was not found.
Possible reasons for this include:
  * You misspelled a built-in dotnet command.
  * You intended to execute a .NET program, but dotnet---logLevel does not exist.
  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.

The dotnet---logLevel in the error message indicates dotnet received --logLevel as its first argument (interpreted as a program/tool name).

Expected Behavior

The extension should either:

  1. Pass the language server path to dotnet:

    dotnet /path/to/.roslyn/Microsoft.CodeAnalysis.LanguageServer --logLevel Information ...
    
  2. Or run the self-contained native binary directly:

    /path/to/.roslyn/Microsoft.CodeAnalysis.LanguageServer --logLevel Information ...
    

Evidence

I created a wrapper script to intercept and log dotnet invocations:

=== Mon Jan 19 03:49:23 PM CST 2026 ===
Called as: /home/deck/.local/bin/dotnet
Args: --logLevel Information --telemetryLevel all --extensionLogDirectory /home/deck/.config/Code/logs/20260119T154917/window1/exthost/ms-dotnettools.csharp
Arg count: 6
  Arg 1: '--logLevel'
  Arg 2: 'Information'
  Arg 3: '--telemetryLevel'
  Arg 4: 'all'
  Arg 5: '--extensionLogDirectory'
  Arg 6: '/home/deck/.config/Code/logs/...'

Notice: No language server path is passed. The first argument is --logLevel.

Settings Ignored

Setting dotnet.server.path in settings.json has no effect:

{
    "dotnet.server.path": "/home/deck/.vscode/extensions/ms-dotnettools.csharp-2.18.16-linux-x64/.roslyn/Microsoft.CodeAnalysis.LanguageServer"
}

The extension logs show it acknowledges the dotnet path but still constructs the command incorrectly:

Dotnet path: /home/deck/.dotnet/dotnet
Activating C# standalone...
waiting for named pipe information from server...
[stderr] Could not execute because the specified command or file was not found.

Inconsistent dotnet Resolution

The extension uses different dotnet executables for different operations:

  • For --info and --list-runtimes calls: Uses the dotnet.dotnetPath setting
  • For language server spawn: Uses dotnet from PATH, ignoring dotnet.dotnetPath

Evidence: When I set dotnet.dotnetPath to a wrapper script directory, the wrapper logged --info and --list-runtimes calls but NOT the language server spawn. The language server spawn only went through my wrapper when I replaced the dotnet in PATH (~/.local/bin/dotnet).

This inconsistency means users cannot reliably configure a custom dotnet path for all extension operations.

Workaround

I created a wrapper script that intercepts the malformed call and runs the language server directly:

#!/bin/bash
if [[ "$1" == "--logLevel" ]]; then
    SERVER="/home/deck/.vscode/extensions/ms-dotnettools.csharp-2.18.16-linux-x64/.roslyn/Microsoft.CodeAnalysis.LanguageServer"
    export DOTNET_ROOT="/home/deck/.dotnet"
    exec "$SERVER" "$@"
else
    exec /home/deck/.dotnet/dotnet "$@"
fi

Important: Due to the inconsistent dotnet resolution bug, this wrapper must be placed in PATH (e.g., ~/.local/bin/dotnet), not just configured via dotnet.dotnetPath. Setting dotnet.dotnetPath alone does not work because the language server spawn ignores that setting.

This confirms the language server binary works correctly when invoked properly.

Additional Notes

  • The language server at .roslyn/Microsoft.CodeAnalysis.LanguageServer is a native ELF binary, not a .NET DLL
  • The binary requires DOTNET_ROOT to be set to locate the .NET runtime
  • This may affect other non-standard Linux installations where .NET is not in the default system location

Steps to Reproduce

  1. Install VS Code from tarball on SteamOS/Steam Deck
  2. Install .NET SDK to ~/.dotnet/
  3. Install C# extension v2.18.16
  4. Open any C# project
  5. Observe language server fails to start with "couldn't create connection to server" error
  6. Check Output > C# panel for the dotnet---logLevel error

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions