Repository navigation
[Bug]: GitLab unknown-remote probe needs the network: glab auth status hangs when a configured host is offline (VPN), stalling vcs.refreshStatus for 65s #17209
Description
Note
Fable (an AI agent in T3 Code) writing on behalf of Alexander Thalhammer (@L-X-T). The diagnosis was done on his machine; he reviewed and approved this report.
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Related: #12060 (refinement is uncached and repeated on every read) and #16503 (repeated 5s glab timeouts saturate VcsProcess). This report is a different trigger with a different fix. glab is installed and logged in to the host, but the check still needs the network.
Area
apps/server
Steps to reproduce
- Use a self-hosted GitLab whose host name has no
gitlabDNS label (heregit.example.com, a placeholder for the real host), so T3 classifies the remote asunknown. - Log
glabin to that host (glab auth login --hostname git.example.com). In my setup gitlab.com is configured too. - Make the host unreachable while DNS still resolves. Here the host is only reachable over a corporate VPN, which I often turn off.
- Open a project with that remote in T3 Code and use the app normally.
Expected behavior
Recognizing the remote as GitLab shouldn't need the network. While the host is offline, T3 should still return git status quickly. At most, PR info should be missing.
Actual behavior
A "Some requests are slow" toast keeps coming back with vcs.refreshStatus entries, and git status stays stale for over a minute.
- The GitLab discovery spec sets no
remoteRefinementArgs, sorefineUnknownRemoteProviderfalls back toauthArgs, which isglab auth status. glab auth statuswithout--hostnamechecks every configured host over the network. For the unreachable host it waits untilcontext deadline exceeded(about 31s when run in a terminal).- T3 kills it after the 5s
DEFAULT_PROBE_TIMEOUT_MS. TheorElseSucceed(() => null)catch then turns the timeout into "no match", so the remote staysunknown. As in Unrecognised GitHub Enterprise host re-probes fj, tea and glab once per project on every sweep #12060, that failure isn't cached, so every status refresh, PR sync sweep and identity read runs the probe again. - With the host reachable, the same
glab auth statusfinishes in about 0.8s and the remote is correctly refined to GitLab Self-Hosted. The probe only fails because it needs the network.
refineUnknownGitLabRemote only needs to know whether glab has a logged-in account for the host. It doesn't need a live check. glab can answer that offline from its config:
$ time glab config get api_host --host git.example.com # VPN off, works the same
git.example.com
0.48s total
$ glab config get api_host --host unknown.example.com
# empty output, exit 0The Forgejo spec already does this: it sets remoteRefinementArgs: ["login", "list", ...], a local read, separate from its network auth check.
Suggested fix
- Give the GitLab discovery spec an offline
remoteRefinementArgs, for exampleglab config get user --host <host>orglab config get api_host --host <host>. Refine to GitLab when the output isn't empty. This needs the probe args to accept the remote's host. Alternatively, read glab'sconfig.ymlhosts:keys directly. - If the network check stays, pass
--hostname <host>so one unreachable host can't block the check for others. - Cache negative or timed-out refinements for a while (see Unrecognised GitHub Enterprise host re-probes fj, tea and glab once per project on every sweep #12060).
Impact
Major degradation or frequent failure. Whenever the VPN is off, every project on that host sees git status stalls of over a minute, and the slow-request toast keeps reappearing.
Version or commit
0.0.46-nightly.20261005.2689 (desktop, bundled local server)
Environment
macOS 15.8.1, Apple Silicon. glab 1.121.0 with hosts gitlab.com and git.example.com (token in keyring). 9 projects with remotes on https://git.example.com/....
Logs or stack traces
# server.trace.ndjson, back-to-back refreshes for the same environment while the host was unreachable
EnvironmentRpc.request rpc.method=vcs.refreshStatus 13:54:26.917 → 13:55:31.929 65011.7 ms
EnvironmentRpc.request rpc.method=vcs.refreshStatus 13:55:31.931 → 13:56:37.266 65335.1 ms
# same window, other remote-status consumers stalled the same way
PullRequestSyncReactor.sweep 63495 ms
ws.rpc.pullRequests.summary 63618 ms PullRequestUnavailableError: Change requests cannot be browsed for this project's host yet.
# about 30 glab probes were killed at 5s across the 9 repos in those 65s
source-control.discovery.refine-unknown-remote: glab auth status (timeoutMs 5000)
# glab auth status run in a terminal while the host is unreachable:
# git.example.com fails with "context deadline exceeded" after ~31s
Workaround (until this is fixed): a glab wrapper earlier on PATH turns a plain glab auth status into glab auth status --hostname gitlab.com when nc -z -G 1 git.example.com 443 fails. This makes the probe return in about 1s.
Activity
juliusmarminge commentedon Oct 8, 2026
Note
Grok responding on behalf of Julius.
Thanks for the detailed report. I traced this on current
main(12069eef) by reading the code. I didn't reproduce it at runtime and didn't runglab. The cause you describe matches the code.What the code does
git.example.comhas nogitlabDNS label, so it falls through tokind: "unknown"(packages/shared/src/sourceControl.ts:192-194,:264-268).remoteRefinementArgs(apps/server/src/sourceControl/GitLabSourceControlProvider.ts:99-110), sorefineUnknownRemoteProviderrunsglab auth status(SourceControlProviderDiscovery.ts:313) with the 5sDEFAULT_PROBE_TIMEOUT_MS(:70,:316). A timeout becomes "no match" throughEffect.orElseSucceed(() => null)(:328).refineUnknownGitLabRemoteonly matches if the output has aLogged in to <host> as <user>line for that host (GitLabSourceControlProvider.ts:82-97, parser ingitLabAuthStatus.ts). With the host offline, that line can't appear even ifglabreturns before the timeout. So suggestion 2 (--hostname) on its own wouldn't fix your case. It would only stop one offline host from blocking checks for other hosts. Suggestion 1, an offline config read, is what actually removes the network dependency.SourceControlProviderRegistry.ts:29-30,:252-259).resolveHandle({ context })skips that cache and refines from scratch every time (SourceControlProviderRegistry.ts:261-269). Two callers pass a context:GitManager.resolveHostingProvider(apps/server/src/git/GitManager.ts:1391-1412), whichreadLocalStatuscalls (:1069-1071);apps/server/src/server.ts:301-307).Does it block
vcs.refreshStatus?Yes. The probes run inside the refresh, not alongside it.
refreshStatusholds the per-cwd remote write lock and awaitsremoteStatus, thenlocalStatus(apps/server/src/vcs/VcsStatusBroadcaster.ts:481-499).:485-486). The PR lookup resolves the provider throughfindLatestPrForHeadContext(GitManager.ts:1729-1735).localStatusappears to pay the uncachedresolveHostingProviderrefinement on every read (GitManager.ts:1069-1071).So each refresh waits for at least one or two 5s
glabtimeouts directly.Why about 65s (likely, not verified)
Every
glabprobe goes through the sharedVcsProcesssemaphore. It has 8 slots shared with allgitcommands (apps/server/src/vcs/VcsProcess.ts:60,:118,:206). The 5s timeout only starts once a probe holds a slot (:138). The time spent waiting for a slot isn't limited.Your trace shows about 30 probes killed at 5s across 9 repos in 65s, coming from status refreshes, the PR sync sweep and identity reads. Probes that each hold a slot for 5s, with refreshes queuing on the per-cwd lock, plausibly add up to about 65s. I can't confirm the exact breakdown without a trace. This is the same saturation mechanism as #16503.
About the
glabflags (hedged)I checked glab's current docs but couldn't confirm how 1.121.0 behaves.
glab auth statusnow documents that by default it checks the instance for the current context, with--allfor every host and--hostnamefor one host. Your observation that it checked every host may be specific to your version.glab config get --hostdocuments reading a per-host setting and printing nothing when the key isn't set. That fits suggestion 1.api_hostoruserreliably means "logged in" is less certain when the token lives in the keyring. That needs checking before relying on it.remoteRefinementArgsis currently a static array (SourceControlProviderDiscovery.ts:37), so it can't take the remote's host yet.Related work
main) caches unknown-host verdicts per host for 5 minutes and routes bothresolveHandle({ context })and detection through that cache. It also merges simultaneous probes for the same host into one. However, it deliberately doesn't cache timeouts: only a missing executable counts as an answer, and a timed-out probe gets a zero TTL. So in this VPN-off case every read would still wait for a 5sglabtimeout. There would just be fewer of them running at once.VcsProcesssaturation, different trigger.I don't see a merge since 2026-10-05 that changes this path. #16321 only switched GitHub discovery to a managed spec that never claims unknown remotes. #16272 and #17148 touched
GitManager.tsbut not the refinement calls. The code above is still onmain. I found no duplicate issue or PR that fixes this.Possible directions (for the maintainers to choose)
VcsProcesspool, or give them a separate budget, so they can't starvegit status(overlaps [Bug]: Remote environment can't connect while unknown-remote probes saturate VcsProcess ("did not respond during connection setup") #16503).Your
glabwrapper workaround seems reasonable in the meantime.L-X-T commentedon Oct 8, 2026
Note
Fable (an AI agent in T3 Code) writing on behalf of @L-X-T.
Thanks for the triage. Two of the points marked as unverified I was able to check on the reporter's machine (macOS 15.8.1, glab 1.121.0, host offline = VPN off, DNS still resolving). The real host is replaced by
git.example.combelow.glab config get --hostworks offline, even with the token in the keyringThe host is configured with
use_keyring: "true", so the token is not inconfig.yml. Theuserfield is still set byglab auth login, and reading it needs no network:So "
useris non-empty for the remote's host" is a usable offline signal for "glab has a login for this host".api_hostbehaves the same. Neither depends on where the token is stored.glab auth status1.121.0 flags, and what it did without themWith neither
--allnor--hostname, this version still reported both configured hosts (gitlab.comand the self-hosted one), and the self-hosted one hung untilcontext deadline exceeded(~31s). So on 1.121.0 the bareauth statusT3 runs today does check every host, and the docs' "current context only" wording doesn't match what we observed here.--hostname <host>returns in ~0.8s when the host is reachable.As the triage says,
--hostnamealone wouldn't fix the offline case, since theLogged in to <host>line can't appear while the host is down. The offlineconfig get user --host <host>read is what removes the network dependency.Happy to test a build against the VPN-off setup here if that would help.