Skip to content

fix(core): prevent silent hang during OAuth auth on headless Linux#26571

Merged
scidomino merged 3 commits intogoogle-gemini:mainfrom
RhysSullivan:fix-keychain-hang-headless-linux
May 6, 2026
Merged

fix(core): prevent silent hang during OAuth auth on headless Linux#26571
scidomino merged 3 commits intogoogle-gemini:mainfrom
RhysSullivan:fix-keychain-hang-headless-linux

Conversation

@RhysSullivan
Copy link
Copy Markdown
Contributor

@RhysSullivan RhysSullivan commented May 6, 2026

Gemini CLI was hanging in my environment, tested these changes and they fixed it for me.

AI generated summary below:

=====

Summary

On headless Linux (WSL, SSH-without-DISPLAY, Docker, CI), gemini hangs silently with no output and never exits when the user has selected oauth-personal auth and there are no cached credentials. There is no error, no log line, no debug output — the process is just deadlocked early in startup, well before the TUI mounts or --debug could help.

Root cause is two compounding issues:

  1. createContentGeneratorConfig eagerly awaits loadApiKey() for every auth type — even LOGIN_WITH_GOOGLE / COMPUTE_ADC, where the resulting geminiApiKey is unused (the function returns at the early branch). loadApiKey() goes through HybridTokenStorageKeychainService, which performs a synchronous-looking probe of the OS keychain.

  2. The keychain functional probe has no timeout on Linux. On macOS there is an explicit security default-keychain pre-check (isMacOSKeychainAvailable, lines 193–220) specifically to avoid blocking popups. Linux gets no equivalent. keytar.setPassword → libsecret → D-Bus → Secret Service: if no Secret Service is running (typical in WSL/SSH/Docker/CI), the call hangs indefinitely. There is no logging at this layer, hence the silent hang.

Repro

# Settings:
$ cat ~/.gemini/settings.json
{ "security": { "auth": { "selectedType": "oauth-personal" } } }
$ ls ~/.gemini/oauth_creds.json
ls: cannot access ...: No such file or directory

# Confirm headless Linux env (no DISPLAY, no Secret Service):
$ env | grep -E '^(DISPLAY|WAYLAND_DISPLAY|SSH_CONNECTION)='
SSH_CONNECTION=...

# Run, observe hang:
$ timeout 15 gemini -p hi
$ echo "Exit: $?"
Exit: 124   # timeout fired; produced 0 bytes of output

Workaround that confirms the cause: setting GEMINI_FORCE_FILE_STORAGE=true (skips the keytar probe) immediately makes gemini produce its real error output instead of hanging.

Fix

1. Skip the API-key load for auth types that don't need it.

createContentGeneratorConfig returned early for LOGIN_WITH_GOOGLE / COMPUTE_ADC after awaiting loadApiKey(). Move the early-return above the load — these auth types never read geminiApiKey, so the work was always wasted, and avoiding it sidesteps the keychain entirely on the OAuth happy path.

2. Bound the keychain functional probe with a timeout.

Promise.race the set/get/delete cycle against a 2s timeout. If the Secret Service doesn't respond, fall back to FileKeychain rather than blocking forever. This mirrors the spirit of the existing macOS pre-check and protects every other code path that hits the keychain (MCP token storage, manual API key save, etc.).

Impact

  • OAuth users on headless Linux: the silent hang is gone; OAuth user-code prompt appears within ~2s.
  • API-key users on headless Linux: the worst case becomes a 2s startup penalty before falling back to FileKeychain, instead of an infinite hang.
  • Anyone with a working Secret Service: no observable change (probe completes well under 2s).

@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 6, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@RhysSullivan RhysSullivan marked this pull request as ready for review May 6, 2026 07:28
@RhysSullivan RhysSullivan requested a review from a team as a code owner May 6, 2026 07:28
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a silent hang issue occurring on headless Linux environments (such as WSL, SSH, or Docker) when using the Gemini CLI. The deadlock was caused by an un-timed-out probe of the OS keychain during startup. By optimizing the authentication flow to skip unnecessary keychain checks and adding a timeout mechanism to the keychain probe, the CLI now gracefully falls back to file-based storage instead of hanging indefinitely.

Highlights

  • Optimized Auth Initialization: Refactored createContentGeneratorConfig to perform an early return for Google-based authentication types, preventing unnecessary and potentially blocking keychain access.
  • Keychain Probe Timeout: Introduced a 2-second timeout for the keychain functional probe in KeychainService to prevent indefinite hangs on headless Linux environments lacking a Secret Service.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the createContentGeneratorConfig function by deferring API key loading until after authentication checks, preventing unnecessary keychain access. Additionally, it introduces a 2-second timeout for the keychain functional probe in KeychainService to prevent the CLI from hanging on headless Linux environments. I have no feedback to provide as there were no review comments.

@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label May 6, 2026
createContentGeneratorConfig eagerly awaits loadApiKey() even when the
caller has selected LOGIN_WITH_GOOGLE / COMPUTE_ADC and the result is
unused. That call walks into HybridTokenStorage → KeychainService, which
on Linux probes libsecret (Secret Service over D-Bus). On environments
without a running Secret Service (WSL, SSH sessions without DISPLAY,
Docker, CI), the probe does not return: keytar's setPassword/getPassword
cycle blocks indefinitely and the CLI hangs with no output, before
anything is rendered or logged.

Two fixes:

1. Move the LOGIN_WITH_GOOGLE / COMPUTE_ADC early-return above the API
   key load so OAuth users never touch the keychain. The eager load was
   wasted work for those auth types regardless.

2. Wrap the keychain functional probe in Promise.race against a 2s
   timeout, mirroring the spirit of the existing macOS pre-check. If the
   Secret Service is unresponsive, the CLI now falls back to
   FileKeychain instead of stalling forever. Other code paths that hit
   the keychain (MCP token storage, manual API key save) get the same
   safety net.

Repro before the fix: on WSL with no D-Bus session and selectedType set
to oauth-personal, run `gemini -p hi`. The process produces zero output
and never exits. After: it reaches the OAuth user-code prompt within ~2s.
@RhysSullivan RhysSullivan force-pushed the fix-keychain-hang-headless-linux branch from 11a59c7 to eb4cba3 Compare May 6, 2026 14:39
@scidomino scidomino self-requested a review May 6, 2026 17:38
Copy link
Copy Markdown
Collaborator

@scidomino scidomino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good but for one nit. Please fix and I will approve.

Comment thread packages/core/src/services/keychainService.ts Outdated
Per review feedback: encapsulate the 2s timeout inside the probe method
itself rather than wrapping it at the call site. Same behavior, but the
timeout is now a property of the functional check rather than something
each caller has to remember to apply.
@scidomino scidomino enabled auto-merge May 6, 2026 19:34
@scidomino scidomino added this pull request to the merge queue May 6, 2026
Merged via the queue into google-gemini:main with commit bb4224f May 6, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants