Repository navigation
Worktree bootstrap fetch hangs for the full 30s timeout when a GUI SSH agent is waiting on key authorization #11930
Description
Activity
Thanks for the tight repro and the 1Password /
git ls-remotetimings. This checks out on currentmain(7235701de) and is still distinct from #10916.What’s going wrong
New-thread New worktree + Start from origin in
apps/server/src/ws.tsalways runsgitWorkflow.fetchRemotebeforecreateWorktree:yield* gitWorkflow.fetchRemote({ cwd: prepareWorktree.projectCwd, remoteName: "origin", refName: prepareWorktree.baseBranch, });
GitVcsDriver.fetchRemotethen runsgit fetch --quiet <remote>(scoped to the selected branch after #11633) withSTATUS_UPSTREAM_REFRESH_ENVand notimeoutMsoverride:const STATUS_UPSTREAM_REFRESH_ENV = Object.freeze({ GCM_INTERACTIVE: "never", GIT_ASKPASS: "", GIT_TERMINAL_PROMPT: "0", SSH_ASKPASS: "", SSH_ASKPASS_REQUIRE: "never", }); // … const options = { env: STATUS_UPSTREAM_REFRESH_ENV, fallbackErrorDetail: `git fetch ${input.remoteName} failed`, };
execute()still appliesDEFAULT_TIMEOUT_MS = 30_000whentimeoutMsis omitted, then surfacesGit command timed out.That matches the traces (fetchRemote30004ms /runGitCommandkilled at exactly 30s) and the mobile card (COULD NOT START TASK+ draft restore).Those five env vars only suppress terminal / askpass prompting. They do not touch an agent speaking over
SSH_AUTH_SOCK. Git inheritsprocess.env(so the socket is present), andIdentityAgentin~/.ssh/configreaches the agent even if the server process never saw that socket. The child sits on the agent handshake; git makes no progress; Effect interrupts at 30s.GitVcsDriverCore.test.ts(makes background upstream status fetches non-interactive) asserts the five variables are set, but theGIT_SSHwrapperexit 1s immediately. It never exercises an agent that blocks.This is why it looks intermittent: it fails when nobody is at the machine to approve the tray prompt, which is exactly the mobile / tailnet case. The 30s knife also fires before 1Password’s own 60s prompt deadline, so a user who does notice the icon still has a short window.
Repo size is a red herring here. 18 refs / 3.5M
.git/ one pack, and the same fetch is ~1.1s once authorized. Directgit ls-remoteunder the driver’s env, left unanswered, ran 60.86s and thencommunication with agent failed— the agent’s timeout, not a transfer timeout.Why this isn’t a duplicate of #10916
Same symptom string, different cause:
#10916 this issue Remote HTTPS SSH + GUI agent (1Password) What git is doing actually transferring a large/stale remote blocked on key authorization; no pack progress Auth healthy ( ls-remote1.61s)agent prompt waiting, then agent timeout Repo ~1503 heads / ~10494 tags; unattended fetch 64.90s 18 refs, 3.5M; authorized fetch ~1.1s Leftovers tmp_pack_*from mid-download killsnone reported #11633 already scoped the bootstrap fetch. That helps #10916’s 10k-tag case. It does nothing for an SSH handshake that never starts the transfer.
Related work that does not close this
- Open PR fix(server): let the start-from-origin fetch outlive the 30s git timeout #10943 (
timeoutMs: nullonfetchRemote) is the right fix for [Bug]: New worktree creation fails when git fetch exceeds the hardcoded 30s timeout #10916 and must stayFixes #10916only. Do not attributeCloses #11930. Lifting the deadline turns a 30s false timeout into a stall until the agent’s own prompt timeout (60s here), then a real auth error. Better message, worse latency for the mobile case. - [Bug]: OrbStack systemd service misses SSH_AUTH_SOCK, causing worktree creation to fail at git fetch #10179 / open PR fix(server): recover the login shell SSH agent #10312 are the inverse:
SSH_AUTH_SOCKmissing under OrbStack systemd / login-shell hydration, so the agent is unreachable (Permission denied (publickey)), not prompting. If fix(server): recover the login shell SSH agent #10312 lands, more service-launched servers will have a socket — and GUI agents on that socket will start hitting this hang instead of a fast publickey failure. - Closed [Bug]: Keeps on asking to unlock the SSH keys even when doing nothing (when using 1Password ssh agent) #1190 / Git fetch running constantly in the background is very annoying #356 / [codex] add configurable automatic git fetch interval #2605 are repeated unlock prompts from the background status fetch (
fetchRemoteForStatus, 5s budget, now configurable / disableable). [codex] add configurable automatic git fetch interval #2605 addedSSH_ASKPASS_REQUIRE=neverand the fetch-interval setting. That closed the askpass UI loop. It does not cover per-app agent authorization overSSH_AUTH_SOCK, and it is not the start-from-origin bootstrap path.
Suggested fix
Do not retune the deadline. Detect an outstanding agent handshake with no fetch progress and fail with an authorization-specific error (and keep the prompt in the project draft). A short “no git/ssh progress” window on an SSH remote is enough to distinguish this from a slow pack. The current
Git command timed out.string points at the network/repo and is why this is hard to self-diagnose.A timeout-only change, including #10943, is the wrong tool for this issue.
Workaround
Move
originto HTTPS and usegh auth git-credential. The reporter verified fetch/ls-remote under the driver’s env (withGIT_SSH_COMMAND=/bin/falseandSSH_AUTH_SOCKunset so SSH cannot sneak back). Alternatively, grant the T3 server process standing approval for the key so the agent does not prompt per request.Triage: confirmed bug on
apps/server. Not a duplicate. Accepting for a server fix. #10943 must not close this.- Open PR fix(server): let the start-from-origin fetch outlive the 30s git timeout #10943 (
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.acceptedfeature request acceptedfeature request acceptedvia-triageFiled through npx t3 triageFiled through npx t3 triage
on Sep 15, 2026
What happened
The error shown on mobile:
Diagnosis
Starting a thread with New worktree + Start from origin runs
fetchRemoteinws.ts, which callsGitVcsDriver.fetchRemotewith notimeoutMsand so inheritsDEFAULT_TIMEOUT_MS = 30_000.When
originis an SSH remote and the user's agent is a GUI agent that requires authorization for the requesting application (1Password, Secretive, Yubikey touch), the agent raises an approval prompt. When the request comes from a background app, that prompt is a passive tray notification rather than a focused window.sshblocks on the agent socket, git makes no progress, and the driver kills it at 30s reportingGit command timed out.STATUS_UPSTREAM_REFRESH_ENVsetsGCM_INTERACTIVE=never,GIT_ASKPASS="",GIT_TERMINAL_PROMPT=0,SSH_ASKPASS=""andSSH_ASKPASS_REQUIRE=neverspecifically to stop auth from hanging, andGitVcsDriverCore.test.tsasserts all five reach git. The guard is incomplete: those variables govern terminal and askpass prompting only, and have no effect on an agent prompting overSSH_AUTH_SOCK. The test stubsGIT_SSHwith a wrapper thatexit 1s immediately, so it verifies the variables are set but never exercises an agent that blocks.Note that
IdentityAgentin~/.ssh/configoverridesSSH_AUTH_SOCK, so the agent is reached regardless of what environment the server process inherits. This is not an environment-propagation problem.Three things make this hard to self-diagnose:
Git command timed out, pointing at the network or the repo, when the real cause is a pending key authorization.This is orthogonal to repo size. The repo here is 18 refs, 3.5M
.git, 1 pack, and fetches in ~1.1s once authorized.Note for #10943:
timeoutMs: nullconverts the 30s timeout into a stall lasting until the agent's own prompt timeout, after which git fails with a genuine auth error. Better message, worse latency. A targeted fix would detect an outstanding agent handshake with no fetch progress and surface an authorization-specific error, rather than tuning the deadline.Steps to reproduce
IdentityAgentat it in~/.ssh/config.origin(git@github.com:<user>/<repo>.git).Git command failed in GitVcsDriver.fetchRemote: Git command timed out.No thread row is persisted and the prompt returns to the project draft.A thread on the same project without a worktree succeeds, because no network fetch occurs.
Version
0.0.41-nightly.20260914.1707(desktop Nightly app). Contains #11633.Environment
macOS 27.0.0 arm64, Node v24.18.1, desktop Nightly app as server, mobile app as originating surface, 1Password 8 as SSH agent.
Evidence
T3 Code trace spans (UTC): ws.rpc.orchestration.dispatchCommand 30101ms Failure fetchRemote 30004ms Failure GitVcsDriver.fetchRemote 30004ms Failure git.args_count=3 runGitCommand 30001ms Interrupted runGitCommand started 15:38:19.061, killed 15:38:49.061 1Password agent log, same window (UTC): 15:38:19.548 op-ssh-agent: Notifying user through tray icon that they have a background prompt waiting 15:39:19.400 op-ssh-agent: ssh authorization prompt timed out Second occurrence, same pattern: 16:14:51 background prompt waiting 16:15:50 ssh authorization prompt timed out Direct reproduction outside the app, agent authorization left unanswered, running git under the driver's exact environment: git ls-remote git@github.com:<user>/<repo>.git HEAD -> 60.86s, then: sign_and_send_pubkey: signing failed for ED25519 ".../id_ed25519" from agent: communication with agent failed Agent log: ssh authorization prompt timed out The runGitCommand child span confirms git was spawned and ran the full budget before Effect interrupted it. The same fetch completes in ~1.1s once the agent request is authorized.Related issues
#10916 is the same symptom caused by a genuinely slow fetch on a large repo; this fails on a 3.5M repo whose fetch takes ~1.1s, so the cause is distinct. #10179 is the inverse shape,
SSH_AUTH_SOCKmissing entirely under OrbStack systemd, where the agent is unreachable rather than prompting. #1190 (closed) covers repeated unlock prompts in the UI, not a blocked fetch.Fix applied or workaround
Moving the project's
originto HTTPS with thegh auth git-credentialhelper removes the SSH agent from the path. Verified on the affected machine, running git under the driver's exact environment withGIT_SSH_COMMAND=/bin/falseandSSH_AUTH_SOCKunset so no SSH fallback is possible:The credential helper authenticates correctly despite
GIT_ASKPASS=""andGIT_TERMINAL_PROMPT=0. Disabling per-request approval for the SSH key is the alternative if SSH remotes must be kept.Filed by
claude (opus-5) via t3 triage