[Bug]: Desktop picks the next free port before checking home ownership, so an SSH client's managed server turns startup into a permanent lockout with unactionable advice
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 52/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- typescript
Hướng nghiên cứu
Read apps/desktop/src/app/DesktopApp.ts first to trace resolveDesktopBackendPort, then compare the ownership checks in packages/ssh/src/tunnel.ts and the lock handling in apps/server/src/serverOwnership.ts. Check how apps/desktop/src/backend/DesktopBackendManager.ts and DesktopBackendPool.ts handle exit code 78 and show the refusal dialog. Done means startup detects an existing owner before spawning and gives accurate guidance; the issue asks for at least avoiding a doomed spawn.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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
Host A is a macOS desktop with the default home ~/.t3. Host B is another machine with a T3 Code SSH environment pointing at A.
- On A, quit T3 Code desktop. Nothing owns
~/.t3/userdataany more. - On B, its SSH environment launches its managed server through
~/.t3/ssh-launch/<key>/run-t3.sh. With no live runtime record, the script picks a free port and runst3 serve --host 127.0.0.1 --port 3773 --base-dir ~/.t3, which acquires~/.t3/userdata/server-owner.sqliteand serves on 3773. - On A, open T3 Code desktop with the default Local environment.
- Startup scans for a port. 3773 is in use, so it selects 3774 (
startPort: 3773,port: 3774) and spawns its backend child there. - The child exits 78 with
ServerAlreadyRunningError. The failure is the ownership lock, not the port. Exit 78 routes toonStateDirOwned, the "This T3 home is unavailable" box is shown, and the app quits. - Follow the dialog.
t3 status --base-dir ~/.t3reportsService: not installed, so there is nothing fort3 updateort3 service uninstallto act on. The real owner is the SSH-launched server, which the dialog never mentions. - Try stopping the owner by hand. B's supervisor relaunched it in 2 s, and again in 9 s, after SIGTERM to the server each time, so there is no window in which to open the app.
The only escape found was quitting T3 Code on B (or disabling that SSH environment), then opening the desktop.
Expected behavior
The desktop should decide whether it may start from home ownership, not from port availability. Before spawning it can read ~/.t3/userdata/server-runtime.json (pid, port, version) and the server-owner.sqlite lock, which packages/ssh/src/tunnel.ts already does on the SSH side, and then:
- if a live owner already serves this home, adopt it (or ask the user) rather than starting a second server, and
- if it must refuse, name the actual owner and how it was started (managed server launched over SSH from
<peer>, pid and version), instead of advisingt3 service uninstallfor a service that is not installed.
At minimum it should not spend a doomed spawn on a home it cannot possibly own.
Actual behavior
resolveDesktopBackendPort treats "the default port is busy" as "use the next free port". That check says nothing about whether the home is owned, so the desktop spawns a second server for the same ~/.t3/userdata on 3774. That server correctly refuses to start (ServerAlreadyRunningError, exit 78), the app quits, and the dialog blames a background service that does not exist.
The asymmetry is the clearest signal that this is a gap rather than a design choice: in the reverse direction the SSH launcher handles it correctly. Once the desktop owns the home, ~/.t3/ssh-launch/<key>/managed flips from managed to external and the remote client adopts port 3773 instead of launching a rival server. The desktop has no equivalent adoption or ownership preflight anywhere: grep -rn "serverRuntimeState\|server-runtime.json\|server-owner" apps/desktop/src returns no matches.
Impact
Blocks work completely. The app quits with no in-app recovery path, and the advertised remedy is a no-op in this configuration.
Version or commit
- Desktop:
0.1.9-nightly.20261111.4501(auto-updated to0.1.9-nightly.20261111.4515during triage; the failure reproduced on 4501) - SSH-launched server, pinned by the remote client:
0.1.7-nightly.20261104.4151 t3CLI:v0.1.9-nightly.20261111.4501
Environment
- Host A: macOS 27.2.1 (26B131), arm64, desktop app, Local environment enabled, no background service installed, home
~/.t3(400 MBstatev2.sqlite). - Host B: T3 Code desktop with an SSH environment to A, over the LAN (A
192.168.50.71, B192.168.50.115). ~/.t3/ssh-launch/c0a8a54905bb042c/existed before the incident (created weeks earlier) and pinned progressively older servers over time:0.1.3-nightly.20261027.3748,0.1.5-nightly.20261029.3877,0.1.7-nightly.20261104.4151.
Logs or stack traces
~/.t3/userdata/logs/server-child.log (two consecutive startup attempts):
{"annotations":{"component":"desktop-backend-child","runId":"efc82f9c56be","instanceId":"primary","phase":"START","details":"pid=86944 port=3774 cwd=/Users/skumar"}}
ERROR (#2): ServerAlreadyRunningError: A T3 Code server already owns /Users/skumar/.t3/userdata. Stop that server, or use a separate T3 home and pair with it, then retry. No server was stopped. server-owner.sqlite is the ownership lock; do not delete it while a server is running.
{"annotations":{"component":"desktop-backend-child","runId":"efc82f9c56be","phase":"END","details":"pid=86944 code=78"}}
{"annotations":{"component":"desktop-backend-child","runId":"dd7b847d4e89","phase":"START","details":"pid=87403 port=3774 cwd=/Users/skumar"}}
~/.t3/userdata/logs/desktop.trace.ndjson, the port decision that makes it Doomed:
{"attributes":{"scope":"desktop","runId":"efc82f9c56be","component":"desktop-bootstrap","port":3774,"startPort":3773,"effect.logLevel":"INFO"}}
The owner holding the lock, and that it is not a service:
$ lsof ~/.t3/userdata/server-owner.sqlite
COMMAND PID USER FD TYPE ... NAME
t3 98563 skumar 13u REG ... /Users/skumar/.t3/userdata/server-owner.sqlite
$ cat ~/.t3/userdata/server-runtime.json
{"version":1,"pid":98563,"host":"127.0.0.1","port":3773,...,"serverVersion":"0.1.7-nightly.20261104.4151"}
$ t3 status --base-dir ~/.t3
This machine
Service not installed
T3 Connect off
Local network off
SSH-launch state while it held the home, and after the desktop won it:
# during the lockout
pid=93146 port=3773 managed=managed
# after quitting the app on B and opening the desktop: the SSH side adopts it
pid= port=3773 managed=external
Relaunch timing after kill -TERM on the SSH-launched server (no window to start the app):
t=1s free
t=9s SERVER_UP pid=98563 # first attempt
... (killed again) ...
t=1s free
t=4s SERVER_UP pid=4699 # second attempt
Code pointers
apps/desktop/src/app/DesktopApp.ts—resolveDesktopBackendPortscans 3773 to 65535 usingnet.canListenOnHostonly, and the call site logsport/startPort.apps/desktop/src/backend/DesktopBackendManager.ts(~line 834) —const stateDirOwned = exitCode === SERVER_EXIT_CODE_STATE_DIR_OWNED;apps/desktop/src/backend/DesktopBackendPool.ts(~line 180) — the dialog text shown foronStateDirOwned.apps/server/src/serverOwnership.ts—ServerAlreadyRunningErrorand the lock; the comment onSERVER_EXIT_CODE_STATE_DIR_OWNEDsays the distinct code exists so supervisors stop restarting, which is why the child dies quietly and the port scan never learns why.packages/ssh/src/tunnel.ts— the launch script already readsserver-runtime.json, adopts a live owner, and flipsmanagedtoexternal.
Related issues
- #22990 — same end state, but it needs a desktop update/restart window of ~8 s. Here there is no race: while B stays connected the desktop can never start, so this is the steady-state version of that report.
- #24225 — service launcher goes idle after an SSH-launched server takes the lock during a restart.
- #22820 — the same dialog is used for two different causes and never mentions turning off the Local environment.
- #34060 — shared
$HOMEacross machines, where the owner lives on another host. Different topology: here the owner is local and the client is remote. - #20250 — "desktop quits instead of offering to connect" was closed as not planned, so this report asks for an accurate refusal and no doomed spawn, not for automatic adoption.
- #27183, #24318 — nearby SSH-launched-server lifetime problems.
Workaround
Quit T3 Code on B (or disable that SSH environment) so B stops relaunching, then open the desktop. Verified on this host: the desktop took the lock on 3773 as 0.1.9-nightly.20261111.4515, and B's launcher then adopted it as external with no further launches.
- Ngôn ngữ chính
- TypeScript
- Star
- 24.8k
- Fork
- 6.4k
- Merge trung bình
- 10 giờ 56 phút
- Pull request đã merge (30 ngày)
- 226
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của pingdotgg/t3code
-
[Bug]: request_secret file delivery has no trailing newline, and the tool text does not say soCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 69/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: Changing the sidebar project filter collapses an expanded Settled shelf back to 10 threadsĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
pingdotgg/t3code#34291 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
Maintainer thường phản hồi trong vòng 1 ngày
-
via-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của pingdotgg/t3code
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 82/100
lingdojo/kana-dojo#33947 · 1 bình luận · 5 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
paperclipai/paperclip#20942 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area: documentation good first issue package: rule-data status: accepting prs
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
status: needs triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
mastra-ai/mastra#30109 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày