Skip to content

SSH local forward survives desktop update and relaunch #14268

Open

Description

@serabi

Summary

After T3 Code Nightly installed an update and relaunched on macOS, an SSH forward from the old desktop process remained open. The new desktop process opened a second forward to the same MacBook Pro on my local network.

What I observed

  • September 28, 2026, 22:05 UTC: T3 opened a forward to my MacBook Pro on local port 62377 (PID 60751).
  • September 29, 2026, 14:28:12 UTC: the desktop trace recorded desktop.updates.install and desktop.updates.installDownloadedUpdate.
  • 14:28:18 UTC: a new desktop instance started.
  • 14:28:37 UTC: it opened a forward to the same MacBook Pro on local port 54619 (PID 60341).
  • After the relaunch, PID 60751 was still listening on port 62377 and had parent PID 1. PID 60341 belonged to the current desktop process.

I found and stopped 12 orphaned T3 SSH forwards in total. The retained trace lets me tie one of them, PID 60751, to this update. Older trace files have rotated away, so I cannot say what left the other 11 running.

Expected behavior

The old desktop instance closes its SSH forwards before the update relaunches T3 Code.

Investigation notes

The retained trace has no successful tunnel-close event for PID 60751 around the update. Events may be lost as the app exits, but the process was still running after relaunch.

The update path stops backend instances before calling quitAndInstall. The updater quit handler permits that quit without waiting for the normal desktop shutdown path. SSH forward cleanup appears to depend on the SSH environment manager closing during shutdown. This is a possible cause, not a confirmed one.

Environment

  • macOS
  • T3 Code Nightly after update: 0.0.43-nightly.20260929.2428
  • Desktop-managed SSH connections

Related report

#4144 reports stale local forwards during SSH reconnects. This report concerns an update and relaunch.

Activity

  1. juliusmarminge commented on Sep 29, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed. This is a real leak on the desktop update quit path, and it is still present on main. It is not a duplicate of #4144.

    installDownloadedUpdate stops backend pool instances, then calls quitAndInstall. That stop exists because app.quit() exits before the runtime scope can run finalizers (apps/desktop/src/updates/DesktopUpdates.ts). The updater listener then sets updaterQuitAllowed and returns immediately, on purpose, so the macOS native relaunch is not cancelled (apps/desktop/src/app/DesktopLifecycle.ts). The following before-quit sees that flag and returns without DesktopShutdown.request.

    The desktop runtime stays blocked on shutdown.awaitRequest (apps/desktop/src/app/DesktopApp.ts), so the layer scope never closes. Local forwards are ssh -N -L children (packages/ssh/src/tunnel.ts). They are only signaled from the SshEnvironmentManager scope finalizer (SIGTERM, then force-kill). A parent exit does not deliver that signal, and -n means the forward does not exit when the parent’s stdin pipe closes. The child is reparented to PID 1 and keeps listening. That matches PID 60751 still bound to port 62377 after the 14:28 UTC relaunch, and the new instance opening a second forward on port 54619.

    #4144 is a different failure: reconnects inside a live desktop process can replace a slow tunnel before the previous child is reaped. #10105 serialized connect and disconnect per target; it does not run on this quit path. The other 11 orphans are not identified by the retained trace, so they may be earlier quits or that reconnect leak. This report stands on the one forward tied to the update.

    A fix has to reap the local ssh children before quitAndInstall, the same way backends are stopped. Routing the updater through the normal async shutdown is not enough: that handler is required to return without delaying the relaunch. The existing tunnel finalizer also stops a managed remote server after killing the local process; this bug only requires the local listener to die so the relaunched app does not stack another forward onto the same host.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Sep 29, 2026
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

    bugSomething 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