anthropics / anthropics/claude-code
[Bug] Interactive startup hangs indefinitely (blank screen) when TERM_PROGRAM=Apple_Terminal (v2.1.237, macOS)
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
## Environment
- Claude Code v2.1.237, native installer binary (arm64 Mach-O at `~/.local/bin/claude`)
- macOS 26.5.2 (Darwin 25.5.0), Apple Silicon
- Shell: zsh; default terminal: macOS Terminal.app
## Summary
Launching `claude` interactively in Terminal.app hangs on a blank screen indefinitely before the first UI paint. The same launch is ready in ~0.5s in iTerm2/WezTerm or with `TERM_PROGRAM` unset. Confirmed in real Terminal.app: `TERM_PROGRAM= claude` starts instantly; plain `claude` hangs.
## Reproduction / evidence (PTY harness, real binary)
Launched `claude` under a Python `pty` harness (setsid, pty slave as stdio), varying only terminal identity:
| Condition | Result |
|---|---|
| `TERM_PROGRAM=Apple_Terminal` (full or minimal env) | emits 13 bytes then silent; **still hung after 240s, no recovery** |
| `TERM_PROGRAM` unset / `""` / `iTerm.app` / `WezTerm` | full UI painted in 0.50–0.69s |
The 13 bytes emitted before the hang: `\x1b7\x1b[r\x1b8\x1b[?25h` (save cursor, reset scroll region, restore cursor, show cursor). No terminal capability queries are sent before the hang, so it is not waiting on a terminal reply.
Not affected by: `--settings '{"tui":"default"}'`, `CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1`, plugin/MCP configuration (reproduces with `--strict-mcp-config`-equivalent trims), minimal environment (HOME/PATH/TERM/SHELL/USER only).
## Process state while hung
`sample ` shows the main thread parked in a bare blocking file open, 100% of samples, CPU time frozen (no growth between t=2s and t=10s):
```
1658 ??? (in 2.1.237) load address ... + 0x196afa8
1658 openat$NOCANCEL (in libsystem_kernel.dylib) + 76
1658 __openat_nocancel (in libsystem_kernel.dylib) + 8
```
Other observations while hung:
- One zombie child is left unreaped; PATH-shim tracing shows startup shells out to `/usr/bin/security find-generic-password -a -w -s "Claude Code-credentials"` (×3) — these complete instantly and are not the block.
- MCP stdio children (spawned before the hang) are alive and idle.
- `lsof` shows nothing unusual; the blocking `openat` target could not be identified without root (lldb attach denied by hardened runtime; no `fs_usage` without sudo).
- `-p`/non-interactive mode is unaffected (full run ~6s including API call).
## Workaround
`TERM_PROGRAM= claude` (or any non-Apple_Terminal value). Guarded alias:
```zsh
[[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && alias claude='TERM_PROGRAM= claude'
```
## Expected
Interactive startup in Terminal.app paints the UI in well under a second, as it does in every other terminal identity.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reproducing the launch with the provided Python PTY harness while varying only TERM_PROGRAM, then compare the process state and emitted bytes. Trace the interactive startup path around the blocking openat and the Apple_Terminal condition; done means Terminal.app paints the UI promptly without the indefinite hang, while other terminal identities remain unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, python, zsh
- Domain
- cli, operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100