Problem running `ty` server for project in WSL
Hi,
This is my LSP setting:
{
"clients": {
"ty": {
"enabled": true,
"command": ["ty", "server"],
"selector": "source.python"
}
}
}
If I open WSL project ty server crushes.
From the LSP log:
# --> ty initialize (1):
{
"processId": 10276,
"clientInfo": {"name": "Sublime Text LSP", "version": "2.6.0"},
"rootUri": "file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api",
"rootPath": "\\\\wsl.localhost\\Ubuntu-20.04\\home\\klo\\projects\\api",
"workspaceFolders": [
{
"name": "api",
"uri": "file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api",
}
],
# ...
}
then:
# <<< ty (1) (duration: 461ms):
{
"capabilities": {
"completionProvider": {"triggerCharacters": ["."]},
"declarationProvider": True,
"definitionProvider": True,
"documentHighlightProvider": True,
"documentSymbolProvider": True,
"executeCommandProvider": {
"commands": ["ty.printDebugInformation"],
"workDoneProgress": False,
},
"hoverProvider": True,
"inlayHintProvider": {},
"positionEncoding": "utf-16",
"referencesProvider": True,
"selectionRangeProvider": True,
"semanticTokensProvider": {
"full": True,
"legend": {
"tokenModifiers": ["definition", "readonly", "async"],
"tokenTypes": [
"namespace",
"class",
"parameter",
"selfParameter",
"clsParameter",
"variable",
"property",
"function",
"method",
"keyword",
"string",
"number",
"decorator",
"builtinConstant",
"typeParameter",
],
},
"range": True,
},
"signatureHelpProvider": {
"retriggerCharacters": [")"],
"triggerCharacters": ["(", ","],
},
"typeDefinitionProvider": True,
"workspaceSymbolProvider": True,
"textDocumentSync": {"change": {"syncKind": 2}, "didOpen": {}, "didClose": {}},
},
"serverInfo": {"name": "ty", "version": "0.0.1-alpha.22"},
}
which results in:
ty: ty failed ty: Cause: Failed to start server ty: Cause: Workspace URL is not a file or directory:
Url {
scheme: "file",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(Domain("wsl.localhost")),
port: None,
path: "/Ubuntu-20.04/home/klo/projects/api",
query: None,
fragment: None,
}
And right after that it reports:
-> ty initialized: {}
-> ty workspace/didChangeConfiguration: {}
-> ty textDocument/didOpen: {'textDocument': {'uri': 'file://wsl.localhost/Ubuntu-20.04/...
and finally:
ty: 2025-10-15 17:07:11.489449800 ERROR Failed to create project for `\\wsl.localhost\Ubuntu-20.04\home\klo\projects\api`: Failed to discover the site-packages directory: Invalid local virtual environment `\\?\UNC\wsl.localhost\Ubuntu-20.04\home\klo\projects\api\.venv`: Could not find a `site-packages` directory for this Python installation/executable. Falling back to default settings
:: [17:07:11.489] <- ty window/showMessage: {'message': 'Failed to load project rooted at \\\\wsl.localhost\\Ubuntu-20.04\\home\\klo\\projects\\api. Please refer to the logs for more details.', 'type': 1}
ty: 2025-10-15 17:07:11.490223200 INFO Defaulting to python-platform `win32`
ty: 2025-10-15 17:07:11.585543400 ERROR panicked at crates\ty_server\src\session.rs:546:30:
ty: Default configuration to be valid: Failed to discover the site-packages directory
ty:
ty: Caused by:
ty: Invalid local virtual environment `\\?\UNC\wsl.localhost\Ubuntu-20.04\home\klo\projects\api\.venv`: Could not find a `site-packages` directory for this Python installation/executable
I reported first in astral's repo thinking the issue is from the server: https://github.com/astral-sh/ty/issues/1362
I even tried to run ty from within WSL as reported in above issue, w/o success:
"settings": {
"LSP": {
"ty": {
"enabled": true,
"command":["wsl", "--shell-type", "login", "--", "ty", "server"],
"selector": "source.python"
}
}
}
However if I open the same WSL project in Zed, ty server works correctly.
What is the URI used by Zed?
The URI file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api looks good to me.
Python 3.14.0 (tags/v3.14.0:ebf955d, Oct 7 2025, 10:15:03) [MSC v.1944 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from urllib.parse import urlparse
>>> urlparse('file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api')
ParseResult(scheme='file', netloc='wsl.localhost', path='/Ubuntu-20.04/home/klo/projects/api', params='', query='', fragment='')
PowerShell also gives the same URI for the UNC path (based on https://superuser.com/questions/1116771/how-can-i-convert-a-unc-windows-file-path-to-a-file-uri-without-using-any-3rd-pa):
PowerShell 7.5.3
PS> ([System.Uri]'\\wsl.localhost\Ubuntu-20.04\home\klo\projects\api').AbsoluteUri
file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api
But I don't use WSL, so I don't know what URI format is expected here (or by the server).
This is from Zed log:
...
2025-10-15T19:31:19+02:00 INFO [lsp] starting language server process. binary path: "ty", working directory: "\\\\?\\UNC\\wsl.localhost\\Ubuntu-20.04\\home\\klo\\projects\\api", args: ["server"]
2025-10-15T19:31:19+02:00 INFO [lsp] starting language server process. binary path: "ruff", working directory: "\\\\?\\UNC\\wsl.localhost\\Ubuntu-20.04\\home\\klo\\projects\\api", args: ["server"]
2025-10-15T19:31:24+02:00 WARN [project::lsp_store] skipping diagnostics update, no worktree found for path "\\\\wsl.localhost\\Ubuntu-20.04\\home\\klo\\projects\\api\\main.py"
...
and these are part of RPC messages:
// Send:
{"jsonrpc":"2.0","id":3,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api/main.py"},"position":{"line":26,"character":50}}}
// Receive:
{"jsonrpc":"2.0","id":3,"result":null}
// Receive:
{"jsonrpc":"2.0","id":2,"result":[{"kind":2,"label":[{"value":"name"},{"value":"="}],"position":{"character":27,"line":10}}]}
// Send:
{"jsonrpc":"2.0","id":4,"method":"textDocument/inlayHint","params":{"textDocument":{"uri":"file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api/main.py"},"range":{"start":{"line":48,"character":1},"end":{"line":88,"character":61}}}}
// Receive:
{"jsonrpc":"2.0","id":4,"result":[{"kind":2,"label":[{"value":"file"},{"value":"="}],"position":{"character":18,"line":49}},{"kind":2,"label":[{"value":"mode"},{"value":"="}],"position":{"character":29,"line":49}},{"kind":2,"label":[{"value":"image_path_or_url"},{"value":"="}],"position":{"character":35,"line":55}},{"kind":2,"label":[{"value":"prompt"},{"value":"="}],"position":{"character":46,"line":55}},{"kind":2,"label":[{"value":"msg"},{"value":"="}],"position":{"character":21,"line":72}},{"kind":2,"label":[{"value":"object"},{"value":"="}],"position":{"character":52,"line":72}},{"kind":2,"label":[{"value":"object"},{"value":"="}],"position":{"character":50,"line":75}}]}
// Send:
{"jsonrpc":"2.0","id":5,"method":"textDocument/hover","params":{"textDocument":{"uri":"file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api/main.py"},"position":{"line":5,"character":38}}}
// Send:
{"jsonrpc":"2.0","method":"$/cancelRequest","params":{"id":5}}
// Receive:
{"jsonrpc":"2.0","id":5,"error":{"code":-32800,"message":"request was cancelled by client"}}
// Send:
{"jsonrpc":"2.0","id":6,"method":"textDocument/hover","params":{"textDocument":{"uri":"file://wsl.localhost/Ubuntu-20.04/home/klo/projects/api/main.py"},"position":{"line":5,"character":38}}}
// Receive:
{"jsonrpc":"2.0","id":6,"result":{"contents":{"kind":"markdown","value":"```python\ndef analyze_image(\n image_path_or_url: str | Unknown,\n prompt: str = Literal[\"Describe this image\"]\n) -> str\n```\n---\n```text\nSimple function to analyze an image using the Qwen VL model via OpenRouter API.\n\nArgs:\n image_path_or_url: Path to an image file, URL to an image, or PIL Image object\n prompt (str): The prompt to use for the model\n\nReturns:\n str: The model's response\n\n```"},"range":{"end":{"character":46,"line":5},"start":{"character":33,"line":5}}}}
A path like \\wsl.localhost\Ubuntu-20.04\home\klo\projects\ is the windows representation of a path within a WSL environment. It is not accessible from within WSL itself.
Either a process running within WSL environment needs to detect this kind of url needing translation to a local path /home/klo/projects/, which is probably unlikely to be implemented, or LSP would need to know about ty running in WSL and translate URI accordingly. It would need to send uri=file:///home/klo/projects/ as if it would run natively on Linux.
Supporting langauge-servers running in WSL requires some extra client-side path translation logic.
Assuming ty running in WSL, LSP would need to handle path translation for following scenarios:
-
project being located in WSL environment as well (translate to local path )
\\wsl.localhost\<distro>\home\klo\projects\->file:///home/klo/projects/ -
project being located on Windows path
C:\Users\klo\projects\->file:///mnt/c/Users/klo/projects/