Open in editor hangs forever when the server runs inside a Docker container reached over SSH
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
What happened
Open in editor doesn't work. My client is Cursor on a Mac, but the T3 server runs inside a VM-hosted Docker container that I reach with gcloud compute ssh --tunnel-through-iap into the VM followed by docker exec -it t3 bash. When I click Open in Cursor, Cursor launches on my Mac and shows "connecting" but the connection runs forever and never opens the workspace.
Diagnosis
The environment is classified as a remote SSH environment, so open-in-editor takes the remote-links path and hands the OS a deep link instead of exec'ing an editor on the server host:
cursor://vscode-remote/ssh-remote+<host><container-path>
built by buildRemoteOpenUrl (packages/contracts/src/editor.ts). This is confirmed by the server traces containing no shell.openInEditor RPC span for the attempts — in remote-links mode the deep link fires entirely client-side (openRemoteEditorUrl in apps/web/src/remoteOpen.ts) and never reaches the server.
The deep link can't ever connect, because ssh-remote+<host> can only address an SSH host, while the workspace lives inside a Docker container reachable only via ssh <VM> && docker exec:
- Cursor/VS Code Remote-SSH connects to the VM, whose filesystem does not contain the container path (
/workspace/repos/<project>), and - Remote-SSH cannot perform the
docker exechop, so it stalls bringing up the remote server / never lands on the right filesystem.
There is no ssh alias or advertised target that resolveRemoteOpenState / RemoteOpenTargets could carry that would open a containerized backend, so both open-in-editor strategies are dead ends for this topology:
remote-links→ generates a link to the VM, which hangs (this report).local-exec→ would exec the editor inside the container, which has no editor onPATH, noDISPLAY, and is the wrong machine anyway.
RemoteOpenTargets.resolveTargets() (apps/server/src/environment/RemoteOpenTargets.ts) also advertises nothing here (no sshd on :22, no Tailscale), so even the direct-remote path has no route — but the failure the user sees is the ssh-alias deep link hanging, not the "No SSH route" dead-end.
Root gap: open-in-editor has no notion of a backend that lives inside a container behind an SSH host. A vscode-remote link would need the attached-container/dev-containers authority (…/attached-container+<hex>…) or an equivalent, not ssh-remote+<host>.
Steps to reproduce
- Run the T3 server inside a Docker container on a remote VM (
npx t3 serveinsidedocker exec -it <container> bash); the VM is reached over SSH (here viagcloud compute ssh --tunnel-through-iap). - Connect the T3 desktop app on a Mac to that server as a remote/SSH environment; have Cursor (or any Remote-SSH-capable editor) installed locally.
- Open a thread in a project whose workspace is a container path (e.g.
/workspace/repos/<project>). - Click Open-in-editor → Cursor.
Expected: Cursor opens the workspace on the Mac.
Actual: Cursor launches and hangs on "connecting" indefinitely; the workspace never opens. No shell.openInEditor span appears in server.trace.ndjson.
Version
0.0.34 (tag v0.0.34, latest stable)
Environment
Client: macOS, T3 desktop app (Electron), Cursor installed locally. Server: T3 0.0.34 in a Linux x64 Docker container (Node v24.19.0) on a GCP VM, reached via gcloud compute ssh --tunnel-through-iap + docker exec. Server bound to 127.0.0.1:8787.
Evidence
# Server host (the container): none of the routes open-in-editor relies on exist
$ ss -ltnp | grep ':22' # -> no sshd
(no output)
$ command -v tailscale # -> absent
$ command -v code cursor codium code-insiders zed # -> none installed
$ ls /.dockerenv # -> present (inside docker)
$ echo "$DISPLAY" # -> empty (headless)
# RemoteOpenTargets therefore advertises nothing (RemoteOpenTargets.ts):
# if (!sshdListening) return [];
# Clients on record (auth_sessions; credential columns omitted):
# desktop MacIntel Electron bearer-access-token <- the failing client
# desktop macOS Chrome browser-session-cookie
# mobile iOS Safari browser-session-cookie
# Workspace roots are container paths (projection_projects):
# /workspace/repos/<project>
# /root/repos
# No server-side editor launch for the click:
$ grep -c 'shell.openInEditor' server.trace.ndjson* # -> 0
# (remote-links deep link fires client-side; never hits the server RPC)
Related issues
#7530 — same open-in-editor local-vs-remote subsystem, but a different failure: there a same-machine browser on a LAN IP is misclassified as remote and dead-ends at a disabled "No SSH route". This report is the opposite end — the environment is correctly remote, a deep link is generated, but ssh-remote+<host> cannot traverse into a Docker container, so it hangs. Not a duplicate.
Fix applied or workaround
Nothing was written to the machine (no DB writes, no source patches). Workaround: use Cursor's Dev Containers: Attach to Running Container — Remote-SSH into the VM, then attach to the t3 container and open the workspace folder. This is the only flow that crosses the docker exec boundary; T3's button cannot drive it.
Filed by
claude (Opus 4.8) via t3 triage
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading packages/contracts/src/editor.ts, apps/web/src/remoteOpen.ts, and apps/server/src/environment/RemoteOpenTargets.ts to trace remote-links and local-exec behavior. Reproduce the container-behind-SSH topology and define a supported open-in-editor path that reaches the container workspace without hanging, while preserving the existing direct SSH and local flows.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, electron, typescript
- Domain
- desktop, devops
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100