bug: TUI hangs indefinitely on "Initializing..." — IdeClient.getInstance() blocks BuiltinCommandLoader in bare terminal
#21477 opened on Mar 6, 2026
Description
Description
Gemini CLI v0.32.1 interactive TUI hangs forever on the "Initializing..." spinner when launched from a bare Linux terminal (not inside any IDE). Headless mode (gemini -p "hello") works perfectly.
Root Cause (Diagnosed)
The hang originates in BuiltinCommandLoader.loadCommands() which awaits ideCommand(). This calls IdeClient.getInstance() → getIdeProcessInfo() → getProcessInfo(pid) which runs ps -o ppid=,command= -p <pid> in a loop, traversing up the process tree looking for a parent IDE.
On certain Linux systems running from a bare terminal, this process traversal never completes — the execAsync('ps ...') call hangs on a specific PID in the ancestor chain.
Because BuiltinCommandLoader never resolves, Promise.allSettled() in CommandService.create() never settles, slashCommands is never set, and the TUI condition (!uiState.slashCommands || !uiState.isConfigInitialized) keeps rendering ConfigInitDisplay ("Initializing...") forever.
Evidence from instrumentation
Added fs.appendFileSync logging to each loader in CommandService.create():
[CMD] loader[0] McpPromptLoader DONE
[CMD] loader[2] FileCommandLoader DONE
# loader[1] BuiltinCommandLoader — NEVER completes
[BUILTIN] isNightly DONE: false
[BUILTIN] ideCommand START
# ideCommand — NEVER completes
config.initialize() completes in ~120ms. The issue is exclusively in the slash command loading phase.
Suggested Fix
Add a timeout to ideCommand() in BuiltinCommandLoader.loadCommands(), or make getIdeProcessInfo() non-blocking with an AbortSignal / timeout. When running from a bare terminal (no IDE detected within N seconds), it should fall back gracefully instead of blocking startup indefinitely.
Example:
// Instead of:
await ideCommand(),
// Use:
await Promise.race([
ideCommand(),
new Promise(resolve => setTimeout(() => resolve(noIdeFallbackCommand), 5000))
]),
Workaround
Replace await ideCommand(), in BuiltinCommandLoader.js with a static no-IDE object:
GEMINI_PATH=$(dirname $(readlink -f $(which gemini)))/../lib/node_modules/@google/gemini-cli
sed -i "s|await ideCommand(),|{ name: 'ide', description: 'Manage IDE integration (disabled)', kind: 'built-in', autoExecute: false, action: () => ({ type: 'message', messageType: 'info', content: 'IDE integration is not available.' }) },|" \
"$GEMINI_PATH/dist/src/services/BuiltinCommandLoader.js"
Environment
- OS: Ubuntu 24.04+ (Linux 6.17.0-14-generic, x86_64)
- Gemini CLI: v0.32.1
- Node.js: v24.14.0
- Terminal: GNOME Terminal / bare terminal (NOT inside VS Code, Cursor, or any IDE)
- Shell: bash
Steps to Reproduce
- Install Gemini CLI on Ubuntu Linux:
npm install -g @google/gemini-cli - Authenticate:
gemini -p "hello"(works fine in headless) - Launch interactive TUI from a bare terminal:
gemini - Observe: TUI shows logo, briefly flashes "Waiting for auth...", then stays on "Initializing..." forever
- Confirm headless works:
gemini -p "hello"responds normally
Related Issues
- #13986 (TUI stuck at Initializing — attributed to MCP, but may also be this bug)
- #20433 (Initializing hang due to ripgrep — different root cause, same symptom)