Skip to content

[Bug]: WSL-only mode stuck on "Connecting to WSL..." forever when the WSL backend keeps crashing on startup #14393

Description

@NightHunter30

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

  1. On Windows, go to Settings > Connections, set the WSL backend to a distro (Ubuntu-22.04 here) and pick "Use only WSL". The app relaunches.
  2. The WSL backend fails to start. For me it crashed on every start, see the logs below. The bundled runtime needed libatomic.so.1, which my Ubuntu 22.04 didn't have. So it fell back to the mounted server tree, and that died with Cannot find module '@yuuang/ffi-rs-linux-x64-gnu'.
  3. The app sits on "Connecting to WSL..." and never gets past it.

You can also hit it by making the backend unreachable instead of crashing, e.g. sudo iptables -I INPUT -p tcp --dport <port> -j DROP inside the distro before launching.

Expected behavior

If the WSL backend can't come up, the app should show an error and fall back to the Windows backend for that launch, like it already does when the WSL preflight fails. At minimum it should get me to a window where I can turn WSL-only off.

Actual behavior

The splash never closes. It has no buttons, and clicking the taskbar icon just brings the splash back, so there's no way to reach Settings. The logs show the backend exiting with code 1 and being restarted every ~10s with no limit. One session had 62 restarts in 13 minutes before I killed it. The only way out was ending it in Task Manager and setting "wslOnly": false in desktop-settings.json by hand.

From reading the code on main (0fcd5f9): the splash only closes once the primary backend reports ready. WSL preflight failures fall back to Windows, but once preflight passes there's no limit:

I have a small fix: after 3 consecutive startup failures in wsl-only mode, show an error and use the existing in-memory Windows fallback for that launch. The desktop tests pass with it, and the new test hangs without it. I'll open a PR and link it here.

Probably related: #3709, #4535, #5967, #13738

Impact

Blocks work completely

Version or commit

0.0.44 (Windows desktop)

Environment

Windows 10 22H2 (19045.6466), WSL 3.0.1.0 (NAT), Ubuntu 22.04

Logs or stack traces

# desktop.trace.ndjson, repeats every ~10s
wslPreflight: "Could not stage the WSL runtime; launching from the mounted server tree instead." reason: "WSL runtime archive does not contain a working t3 executable"
probeReadiness: Interrupted
scheduleRestartFiber: "backend exited unexpectedly; restart scheduled" reason: "code=1"

# server-child.log, every run
Error: Cannot find module '@yuuang/ffi-rs-linux-x64-gnu'
Require stack:
- /mnt/c/Users/<me>/.t3/userdata/wsl-server-tree/0.0.44/node_modules/ffi-rs/index.js
code: 'MODULE_NOT_FOUND'

# running the bundled runtime by hand inside the distro
$ ./t3 --version
./t3: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory

Screenshots, recordings, or supporting files

No response

Workaround

Kill T3 Code in Task Manager, set "wslOnly": false in %USERPROFILE%\.t3\userdata\desktop-settings.json, and relaunch.

In my case, sudo apt-get install -y libatomic1 in the distro also fixed the crash itself.

Activity

  1. added
    bugSomething is broken or behaving incorrectly.
    needs-triageIssue needs maintainer review and initial categorization.
    on Sep 30, 2026
  2. juliusmarminge commented on Sep 30, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed on current main. In wsl-only mode, the "Connecting to WSL…" splash stays up until the primary backend reports ready, and it has no controls, so a backend that never becomes ready leaves you no way back to Settings. Preflight failures are already capped (MAX_PREFLIGHT_FAILURE_ATTEMPTS), and handlePrimaryPreflightFailure falls back to Windows. A backend that passes preflight and then dies isn't capped: scheduleRestart only limits the delay (500ms, doubling, up to 10s), never the number of attempts, which matches the ~10s restart loop. A process that stays up but never answers is the other loop: probeReadiness keeps retrying on a 60s budget for as long as the child is alive.

    The two crashes in your log explain why preflight passes and the process still exits:

    1. The staged runtime's readiness check runs t3 --version with stderr discarded (runtime_entry_runs). Any dynamic-linker failure, including the missing libatomic.so.1 on Ubuntu 22.04, gets reported as "WSL runtime archive does not contain a working t3 executable", and the install falls through to the mounted server tree. That fits libatomic1 making ./t3 --version work. The archive can be intact while the binary still can't run on that distro, and the linker error never reaches desktop.trace.ndjson.

    2. The mounted tree is the Windows server sidecar (server.asar extracted under wsl-server-tree), installed for win32, so ffi-rs's optional @yuuang/ffi-rs-linux-x64-gnu binding isn't in it. Server startup requires @ff-labs/fff-node from WorkspaceSearchIndex.ts, which loads ffi-rs, and Linux Node throws MODULE_NOT_FOUND. The mounted-tree preflight only requires node-pty (whose Linux prebuild ships inside that package), so preflight reports ready and the exit is treated as an unexpected crash rather than a preflight failure. The code comment saying this fallback is recoverable doesn't hold for this tree.

    This isn't a duplicate of open issue #3709 (login-shell Node older than 22.16 exits 0 before binding), closed issue #4535 (slow /mnt/c boot; the readiness probe now retries while the process is alive), closed issue #5967 (same splash, but no logs), or open issue #13738 (dual mode with a healthy backend that Windows can't reach at the NAT address). Those can show the same splash, but the lockout here comes from an uncapped failure after preflight in wsl-only mode.

    An in-memory Windows fallback after repeated startup failures is the right recovery. It has the same shape as the non-fatal preflight path (applyWslWindowsFallbackInMemory), so wslOnly stays set for the next launch. It needs to cover both loops: exits before ready, and a live process whose readiness probes keep failing (the iptables case). That fallback won't make the staged runtime run without libatomic.so.1, and it won't make the Windows sidecar load ffi-rs on Linux. Those are separate fixes.

  3. added
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    and removed
    needs-triageIssue needs maintainer review and initial categorization.
    on Sep 30, 2026
  4. HolzmannSpace commented on Oct 7, 2026

    @HolzmannSpace

    Same crash loop here on T3 Code 0.0.46-nightly.20261007.2761, Windows 11, WSL Ubuntu 22.04.1, Node v24.21.0 via nvm. libatomic1 was not installed.

    One more data point for the fallback path: ffi-rs is not the only native package with missing Linux binaries in wsl-server-tree. The tree only ships the win32 variants of:

    • @yuuang/ffi-rs (missing @yuuang/ffi-rs-linux-x64-gnu@1.3.7)
    • @napi-rs/keyring (missing @napi-rs/keyring-linux-x64-gnu@1.3.0)
    • @ff-labs/fff-node (missing @ff-labs/fff-bin-linux-x64-gnu@0.9.4)

    node-pty is fine since it bundles prebuilds for all platforms.

    After unpacking those three into wsl-server-tree/<version>/node_modules, all modules load in WSL Node and the backend starts. So a fix for the fallback tree needs to include all three Linux packages (and probably the -musl variants for Alpine distros), not just ffi-rs.

  5. AltinEtemaj commented on Oct 9, 2026

    @AltinEtemaj

    Same symptom here on T3 Code 0.0.45 (Windows 11, WSL 2.6.1, Debian 12 bookworm). Root cause was a missing libatomic1 package in the distro. Posting the full chain in case it helps others.

    Symptoms

    • Stuck on "Connecting to WSL…" forever
    • server-child.log loops on: Error: Cannot find module '@yuuang/ffi-rs-linux-x64-gnu' (require stack in wsl-server-tree/0.0.45/node_modules/ffi-rs/index.js)
    • desktop.trace.ndjson: Could not stage the WSL runtime; launching from the mounted server tree instead. with reason WSL runtime installation failed (exit 1): WSL runtime archive does not contain a working t3 executable

    What's actually happening

    1. The staged runtime binary ~/.t3/wsl-runtime/sha256-…/t3 is dynamically linked against libatomic.so.1 (visible in ldd). The default Debian 12 WSL image doesn't include libatomic1, so the binary can't start and staging fails.
    2. T3 then falls back to the mounted Windows server tree (%USERPROFILE%\.t3\userdata\wsl-server-tree\<version>), which only contains the win32 native bindings (@yuuang/ffi-rs-win32-*), so the backend crashes on the missing Linux binding and gets restarted in a loop.

    The Node version was fine here (v24.21.0 was selected), so this is not the #3611 problem.

    Fix

    sudo apt-get update
    sudo apt-get install -y libatomic1

    Then quit T3 Code completely (including the tray icon) and start it again. You can check that the staged runtime works with:

    ~/.t3/wsl-runtime/sha256-*/t3 --version

    Gotcha: if apt refuses with "Unmet dependencies" because of some other broken package (in my case a half-installed google-chrome-stable), apt won't install anything until that's resolved. Run sudo apt --fix-broken install or remove the broken package first.

    Suggestion: "archive does not contain a working t3 executable" hides the real loader error. Surfacing the stderr of the probe (e.g. error while loading shared libraries: libatomic.so.1) or checking for libatomic.so.1 during preflight would make this self-explanatory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions