google-gemini / google-gemini/gemini-cli

Interactive TUI renders but never subscribes to stdin — all keyboard input is ignored

Open
#28,799 7 comments 0 reactions 0 assignees View on GitHub
area/core effort/large kind/bug priority/p1 status/manual-triage
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

### What happened?

The interactive TUI renders completely — banner, tips, the folder-trust dialog, the auth-selection dialog, and eventually the input prompt — but **no keyboard input is ever processed**. Digits, arrows, Enter, plain characters: nothing changes the screen, ever. The process stays alive and idle.

This is not a rendering hang and not a TTY problem. The process **never subscribes to terminal input at all**.

### Evidence

With the TUI up and waiting, on the main CLI process:

1. **The tty fd is absent from every epoll set.** Dumping `/proc//fdinfo/` for all three epoll instances shows no `tfd` entry for fd 0 or for the separate `/dev/pts/N` descriptor the CLI opens. The main thread sits in `epoll_pwait(..., -1, ...)` forever on a set that contains only pipes and eventfds.

2. **No bytes are ever read.** `rchar` in `/proc//io` does not increase by a single byte across repeated keypresses, while the terminal itself is in raw mode (`stty -a` on the pts reports `-icanon -echo -isig`, so the CLI did call `setRawMode(true)`).

3. **strace confirms the capability query completes, then nothing follows.** Launching under `strace -ff -yy -e trace=read,ioctl,epoll_ctl,epoll_wait`:

```
ioctl(23, TCSETSW, {c_iflag=IUTF8, ... c_lflag=ECHOE|ECHOK|ECHOCTL|ECHOKE, ...}) = 0
read(23, "\33P>|tmux 3.4\33\\\33[?1;2;4c", 65536) = 23
```

The terminal replies to `\e[>q` (name) and `\e[c` (device attributes), but never to `\e[?u` (kitty keyboard) — neither tmux nor VTE support it. After this read there is **not a single `epoll_ctl(EPOLL_CTL_ADD)` for the tty fd** in any traced process, and the typed bytes never appear in any trace.

4. **It is a race, not a deterministic failure.** In one run out of roughly twenty, the tty descriptor *was* present in an epoll set and input worked normally — the typed character appeared in the prompt immediately. Same binary, same terminal, same flags.

### Suspected cause

`TerminalCapabilityManager.detectCapabilities()` attaches a `data` listener to `process.stdin` (flowing mode) and waits up to its 1000 ms timeout. Because the terminal never answers the kitty query, that full timeout is always consumed on terminals like VTE and tmux.

Meanwhile Ink subscribes via `readable`, and `KeypressContext` only calls `setRawMode(true)` when `stdin.isRaw === false` — while raw mode is already enabled by the time that effect runs. Ink's `setRawMode` is what attaches the `readable` listener (guarded by `rawModeEnabledCount === 0`), so the listener is never attached and the fd never enters the event loop.

Mixing flowing-mode (`on('data')`) capability detection with Ink's `readable`-based reader on the same stream looks like the underlying race.

Note: patching the `wasRaw === false` guard to call `setRawMode(true)` unconditionally, in every bundled copy of the chunk, did **not** fix it — so the guard alone is not the whole story.

### Steps to reproduce

Reproduction is timing-dependent; on the affected machine it fails on essentially every launch.

1. On Linux, run `gemini` in GNOME Terminal (VTE) or inside tmux.
2. Wait for the folder-trust dialog, or use `--skip-trust` plus `GEMINI_API_KEY` to reach the input prompt directly.
3. Press digits, arrows, Enter, or type any text.
4. Nothing is registered. Confirm with `grep rchar /proc//io` before and after — the value does not move.

### What did you expect to happen?

Keyboard input to be processed by the TUI.

### Environment

- OS: Linux (kernel 7.0), Wayland
- Terminals: GNOME Terminal (VTE) and tmux 3.4 — both affected
- Node.js: 24.19.0 and 22.23.2 — both affected
- Gemini CLI: 0.50.0, 0.53.1, 0.54.4, 0.55.1 and 0.56.0-nightly — all affected
- Installed globally via npm (user-level prefix, no sudo)

### Ruled out

- Not a TTY issue: a plain Node script in the same terminal does `process.stdin.setRawMode(true)` and receives `a`, ``, `\r` correctly.
- Not configuration: reproduced with a completely empty `HOME`, no settings file, no extensions.
- Not the relaunch wrapper: `GEMINI_CLI_NO_RELAUNCH=1` behaves identically, with a single process holding the tty.
- Not `ui.renderProcess`: setting it to `false` changes nothing.
- Not the secret service, network reachability, `io_uring` (`UV_USE_IO_URING=0` makes no difference), or terminal resize (SIGWINCH does not wake it).
- Non-interactive mode (`gemini -p "..."`) works perfectly.

Possibly related: #23297 (Enter does nothing), #23480 (a different mechanism — a background process stealing stdin — but the same user-visible symptom).

Contributor guide

Open the contributing guide

Research direction

Trace TerminalCapabilityManager.detectCapabilities(), its process.stdin data listener and timeout, then compare that lifecycle with Ink's readable-based reader and KeypressContext.setRawMode(true), including rawModeEnabledCount. Reproduce under VTE or tmux with strace and verify the tty receives an epoll subscription and keyboard bytes; done means the TUI consistently processes input without relying on the timing race.

Written by the indexing model from the issue text.

Assessment

Tech stack
nodejs, typescript
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.