Before submitting
Area
apps/desktop
Steps to reproduce
-
Install and start T3 Code desktop on Windows.
-
Use T3 Code 0.0.28.0 / file version 0.0.28.
-
In Settings, enable the new WSL support for the Ubuntu WSL distro. The persisted desktop settings after this were:
{"wslBackendEnabled":true,"wslDistro":"Ubuntu","wslOnly":true}
-
Let the app restart.
-
Restart the app again, or uninstall and reinstall the app.
-
Install PowerShell 7 and Git for Windows, restart T3 Code, then enable WSL support again.
Expected behavior
The desktop app should connect to the WSL backend, or it should fail with an actionable error and provide a recoverable path back to the Windows backend.
Uninstalling/reinstalling should also not leave the app permanently stuck in a WSL-only startup path without an obvious recovery option.
Actual behavior
The app remains on the splash state showing connecting to WSL....
Restarting does not fix it. Uninstalling and reinstalling does not fix it because %USERPROFILE%\.t3\userdata\desktop-settings.json still contains the WSL-only settings.
Installing PowerShell 7 and Git for Windows did not fix the WSL startup loop. After installing PowerShell 7, pwsh.exe is found, so the original spawn pwsh.exe ENOENT warning is no longer the active blocker.
In the logs, WSL preflight succeeds, then the backend exits before readiness and the desktop keeps scheduling restarts. The app polls the WSL backend URL, but the child process exits with code=0 before it becomes ready. No Linux-side process ever listens on the selected WSL backend port.
Impact
Blocks work completely
Version or commit
T3 Code desktop 0.0.28.0 / file version 0.0.28
Environment
-
Windows desktop app
-
Windows version: 10.0.26200.8655
-
WSL distro: Ubuntu, WSL version 2, state Running
-
T3 settings after enabling WSL support:
{"wslBackendEnabled":true,"wslDistro":"Ubuntu","wslOnly":true}
-
Initially, Windows pwsh.exe was not available on PATH:
where.exe pwsh
INFO: Could not find files for the given pattern(s).
-
After installing PowerShell 7, pwsh.exe is found:
C:\Users\mstep\AppData\Local\Microsoft\WindowsApps\pwsh.exe
-
Git for Windows is installed and works by absolute path:
C:\Program Files\Git\cmd\git.exe --version
git version 2.54.0.windows.1
-
There was already a WSL-side npx t3 process listening on port 3773, so the Windows desktop selected backend port 3774.
Logs or stack traces
Initial desktop log excerpts, redacted to remove user-specific paths:
WARN component=desktop-shell-environment probe=powershell-no-profile executable=pwsh.exe
cause: Error: spawn pwsh.exe ENOENT
WARN component=desktop-shell-environment probe=powershell-profile executable=pwsh.exe
cause: Error: spawn pwsh.exe ENOENT
INFO component=desktop-bootstrap selected backend port via sequential scan
port: 3774
startPort: 3773
INFO component=desktop-window connecting splash shown
# WSL preflight in desktop.trace.ndjson appeared to complete successfully:
# - probeDistros success
# - windowsToWslPath success
# - ensureNodePty success
# - getDistroIp success
# Then desktop polled the WSL backend endpoint:
# http://172.x.x.x:3774/.well-known/t3/environment
ERROR component=desktop-backend-instance:primary backend exited unexpectedly; restart scheduled
reason: code=0
delayMs: 500
After installing PowerShell 7 and Git for Windows, re-enabling WSL reproduced the same startup loop without the pwsh.exe ENOENT blocker.
Fresh WSL-mode behavior:
# WSL preflight still succeeds:
# - probeDistros success
# - windowsToWslPath success
# - ensureNodePty success
# - getDistroIp success
# Desktop polls:
http://172.19.227.101:3774/.well-known/t3/environment
# server-child.log repeats child starts and clean exits with no stdout/stderr:
backend child process session start ... runId=d98663cc90e4 ... pid=3464 port=3774 cwd=C:\Users\mstep
backend child process session end ... runId=d98663cc90e4 ... pid=3464 code=0
Captured T3 WSL backend child command line from Windows process inspection:
wsl.exe -d Ubuntu --exec env \
"PATH=/home/stepanek/.nvm/versions/node/v18.20.8/bin:...:/mnt/c/Program Files/Git/cmd:..." \
/home/stepanek/.nvm/versions/node/v18.20.8/bin/node \
/mnt/c/Users/mstep/AppData/Local/Programs/t3code/resources/app.asar.unpacked/apps/server/dist/bin.mjs \
--bootstrap-fd 0
The child exits with code=0 before readiness. Since there is no server output at all in this path, this looks like either the WSL backend bootstrap payload/FD path is failing before logging, or the server process is treating the bootstrap input as complete/empty and exiting cleanly.
No Linux-side process ever listens on 3774; ss -ltnp in WSL only shows the existing unrelated/local 127.0.0.1:3773 T3 server.
After disabling WSL mode, the Windows backend produces normal server logs, for example:
runId=f4c7297cd553
Listening on http://127.0.0.1:3774
POST /oauth/token 200
Workaround
Stop the Windows T3 Code process and edit:
%USERPROFILE%\.t3\userdata\desktop-settings.json
Change the settings from:
{"wslBackendEnabled":true,"wslDistro":"Ubuntu","wslOnly":true}
to:
{"wslBackendEnabled":false,"wslDistro":"Ubuntu","wslOnly":false}
Then restart T3 Code. The app boots again using the Windows backend on 127.0.0.1:3774.
Confirmed root cause from source/runtime investigation
The WSL preflight is selecting Node v18.20.8 from nvm default, even though the server package declares engines.node = "^22.16 || ^23.11 || >=24.10".
In apps/server/src/bin.ts, the packaged server entrypoint is gated by:
if (import.meta.main) {
Command.run(cli, { version: packageJson.version })...
}
Runtime check on this machine:
/home/stepanek/.nvm/versions/node/v18.20.8/bin/node -> import.meta.main is undefined
/home/stepanek/.nvm/versions/node/v22.22.1/bin/node -> import.meta.main is true
So with Node 18, the bundled WSL backend module loads and exits 0 before the CLI/server starts. That matches the desktop symptom: no WSL server ever listens on the selected port, desktop keeps polling /.well-known/t3/environment, and the splash remains stuck at "connecting to WSL...".
Why preflight misses it: apps/desktop/src/wsl/DesktopWslEnvironment.ts passes the server engine range into the WSL node resolver, but after nvm default leaves an out-of-range node on PATH, the node-pty probe can still succeed on Node 18. The code then returns { ok: true, nodePath, resolvedPath } on probe.exitCode === 0 before enforcing that the selected nodePath satisfies serverPackageJson.engines.node.
Local workaround that makes the Windows-launched WSL probe select a compatible runtime:
source ~/.nvm/nvm.sh
nvm alias default 22.22.1
nvm use 22.22.1
After that, a Windows-launched WSL probe resolves:
nodePath:/home/stepanek/.nvm/versions/node/v22.22.1/bin/node
nodeVersion:22.22.1
importMetaMain:true
Suggested product fix: make WSL preflight fail/fallback when the resolved nodePath does not satisfy the server package engine range, even if the node-pty probe succeeds. Also log the selected WSL nodePath and node -v in the backend launch/preflight logs so this is visible without process inspection.
Before submitting
Area
apps/desktop
Steps to reproduce
Install and start T3 Code desktop on Windows.
Use T3 Code
0.0.28.0/ file version0.0.28.In Settings, enable the new WSL support for the
UbuntuWSL distro. The persisted desktop settings after this were:{"wslBackendEnabled":true,"wslDistro":"Ubuntu","wslOnly":true}Let the app restart.
Restart the app again, or uninstall and reinstall the app.
Install PowerShell 7 and Git for Windows, restart T3 Code, then enable WSL support again.
Expected behavior
The desktop app should connect to the WSL backend, or it should fail with an actionable error and provide a recoverable path back to the Windows backend.
Uninstalling/reinstalling should also not leave the app permanently stuck in a WSL-only startup path without an obvious recovery option.
Actual behavior
The app remains on the splash state showing
connecting to WSL....Restarting does not fix it. Uninstalling and reinstalling does not fix it because
%USERPROFILE%\.t3\userdata\desktop-settings.jsonstill contains the WSL-only settings.Installing PowerShell 7 and Git for Windows did not fix the WSL startup loop. After installing PowerShell 7,
pwsh.exeis found, so the originalspawn pwsh.exe ENOENTwarning is no longer the active blocker.In the logs, WSL preflight succeeds, then the backend exits before readiness and the desktop keeps scheduling restarts. The app polls the WSL backend URL, but the child process exits with
code=0before it becomes ready. No Linux-side process ever listens on the selected WSL backend port.Impact
Blocks work completely
Version or commit
T3 Code desktop
0.0.28.0/ file version0.0.28Environment
Windows desktop app
Windows version:
10.0.26200.8655WSL distro:
Ubuntu, WSL version2, stateRunningT3 settings after enabling WSL support:
{"wslBackendEnabled":true,"wslDistro":"Ubuntu","wslOnly":true}Initially, Windows
pwsh.exewas not available on PATH:After installing PowerShell 7,
pwsh.exeis found:Git for Windows is installed and works by absolute path:
There was already a WSL-side
npx t3process listening on port3773, so the Windows desktop selected backend port3774.Logs or stack traces
Initial desktop log excerpts, redacted to remove user-specific paths:
After installing PowerShell 7 and Git for Windows, re-enabling WSL reproduced the same startup loop without the
pwsh.exe ENOENTblocker.Fresh WSL-mode behavior:
Captured T3 WSL backend child command line from Windows process inspection:
wsl.exe -d Ubuntu --exec env \ "PATH=/home/stepanek/.nvm/versions/node/v18.20.8/bin:...:/mnt/c/Program Files/Git/cmd:..." \ /home/stepanek/.nvm/versions/node/v18.20.8/bin/node \ /mnt/c/Users/mstep/AppData/Local/Programs/t3code/resources/app.asar.unpacked/apps/server/dist/bin.mjs \ --bootstrap-fd 0The child exits with
code=0before readiness. Since there is no server output at all in this path, this looks like either the WSL backend bootstrap payload/FD path is failing before logging, or the server process is treating the bootstrap input as complete/empty and exiting cleanly.No Linux-side process ever listens on
3774;ss -ltnpin WSL only shows the existing unrelated/local127.0.0.1:3773T3 server.After disabling WSL mode, the Windows backend produces normal server logs, for example:
Workaround
Stop the Windows T3 Code process and edit:
Change the settings from:
{"wslBackendEnabled":true,"wslDistro":"Ubuntu","wslOnly":true}to:
{"wslBackendEnabled":false,"wslDistro":"Ubuntu","wslOnly":false}Then restart T3 Code. The app boots again using the Windows backend on
127.0.0.1:3774.Confirmed root cause from source/runtime investigation
The WSL preflight is selecting Node
v18.20.8from nvm default, even though the server package declaresengines.node = "^22.16 || ^23.11 || >=24.10".In
apps/server/src/bin.ts, the packaged server entrypoint is gated by:Runtime check on this machine:
So with Node 18, the bundled WSL backend module loads and exits
0before the CLI/server starts. That matches the desktop symptom: no WSL server ever listens on the selected port, desktop keeps polling/.well-known/t3/environment, and the splash remains stuck at "connecting to WSL...".Why preflight misses it:
apps/desktop/src/wsl/DesktopWslEnvironment.tspasses the server engine range into the WSL node resolver, but after nvm default leaves an out-of-rangenodeon PATH, the node-pty probe can still succeed on Node 18. The code then returns{ ok: true, nodePath, resolvedPath }onprobe.exitCode === 0before enforcing that the selectednodePathsatisfiesserverPackageJson.engines.node.Local workaround that makes the Windows-launched WSL probe select a compatible runtime:
After that, a Windows-launched WSL probe resolves:
Suggested product fix: make WSL preflight fail/fallback when the resolved
nodePathdoes not satisfy the server package engine range, even if the node-pty probe succeeds. Also log the selected WSLnodePathandnode -vin the backend launch/preflight logs so this is visible without process inspection.