pingdotgg / pingdotgg/t3code

[Bug]: `t3 service install` fails on WSL2 — `loginctl enable-linger` is called with no username and cannot resolve a session

Open Beginner friendly
#4,894 2 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

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

apps/server

Steps to reproduce

On Ubuntu under WSL2:

  1. npm install -g t3@latest
  2. t3 service install

Install fails at the final activation step and rolls back.

The rollback itself is clean — no dangling unit is left in ~/.config/systemd/user/, and t3 service status correctly reports not installed. That part works exactly as the code comments describe.

Expected behavior

The systemd user unit is installed, enabled and started, as it is on non-WSL Linux.

Lingering is not actually the obstacle here: on this machine Linger=yes was already set for the user (loginctl show-user $(id -un)Linger=yes), so the step is a no-op that fails purely on argument resolution.

Actual behavior
BootServiceCommandError: Background setup failed while enabling lingering for this user (exit code 1).

Root cause. install runs loginctl enable-linger with no username argument:

https://github.com/pingdotgg/t3code/blob/main/apps/server/src/cloud/bootService.ts#L346

yield* runStep("enabling lingering for this user", "loginctl", ["enable-linger"]);

The comment above it explains the reasoning:

No username argument: loginctl defaults to the calling user, which is always right, while $USER can be stale (su without -l) or unset.

That assumption does not hold under WSL2. XDG_SESSION_ID is unset in a normal WSL2 shell, so logind cannot resolve a session for the caller and the no-arg form fails, while the explicit form succeeds:

$ loginctl enable-linger $(id -un)
$ echo $?
0

$ loginctl enable-linger
Could not enable linger: No such device or address
$ echo $?
1

Note this is not a "systemd is missing" case — systemctl --user is-system-running returns running, and daemon-reload / enable / start all succeed. Only the no-arg enable-linger fails.

Suggested fix

Pass the resolved username explicitly rather than relying on the caller-default:

yield* runStep("enabling lingering for this user", "loginctl", ["enable-linger", os.userInfo().username]);

os.userInfo().username comes from the passwd database for the effective uid, so it avoids the stale/unset $USER problem the current comment is guarding against while also working when there is no logind session.

Alternatively, treat a failing enable-linger as non-fatal when lingering is already enabled (check loginctl show-user <user> for Linger=yes first), since in that case the step has nothing to do.

Impact

Major degradation or frequent failure

(t3 service install and t3 service update are unusable on WSL2 without a workaround. Everything else works well — see Workaround.)

Version or commit

t3@0.0.31

Environment

Ubuntu on WSL2 (kernel 6.18.33.2-microsoft-standard-WSL2), Windows host, node v22.22.1, npm 10.9.4, systemd user manager running, Linger=yes already set.

Logs or stack traces
$ t3 service install
[20:27:02.062] ERROR (#5): BootServiceCommandError: Background setup failed while enabling lingering for this user (exit code 1).
    at .../t3/dist/bin.mjs:17006:71
    at cloud.boot_service.run_step (.../t3/dist/bin.mjs:17062:11)
    at cloud.boot_service.install (.../t3/dist/bin.mjs:17065:17)
    at cli.service.reconcile (.../t3/dist/bin.mjs:19594:24)
    at cli.service.run (.../t3/dist/bin.mjs:19593:196)

$ t3 service status
T3 Code service
  Status: not installed
  Next: Run `t3 service install`.
Workaround

Shim only the one call, for the duration of the install:

mkdir -p /tmp/t3-linger-shim
REAL=$(command -v loginctl)
cat > /tmp/t3-linger-shim/loginctl <<EOF
#!/usr/bin/env bash
if [ "\$1" = "enable-linger" ] && [ \$# -eq 1 ]; then
  exec "$REAL" enable-linger "\$(id -un)"
fi
exec "$REAL" "\$@"
EOF
chmod +x /tmp/t3-linger-shim/loginctl

PATH="/tmp/t3-linger-shim:$PATH" t3 service install

With that, the install completes normally and the service is healthy on WSL2:

$ t3 service status
T3 Code service
  Status: installed · t3@0.0.31
  Unit: /home/<user>/.config/systemd/user/t3code.service

$ systemctl --user is-active t3code
active
$ ss -ltnH 'sport = :3773'
LISTEN 0 511 127.0.0.1:3773 0.0.0.0:*

Cold start was ~3s with the data dir on ext4, and Claude Code / Codex / Grok providers were all detected correctly afterwards.

Happy to open a PR with the one-line change if that is welcome — I saw the note in the README that small fixes may be considered.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in apps/server/src/cloud/bootService.ts around line 346 and inspect the install flow's lingering step. Reproduce with t3 service install under WSL2, then verify the change using the explicit username behavior described in the issue. Done means installation completes and t3 service status reports the service as installed and healthy.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux, typescript
Domain
devops, infrastructure
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.