[Bug] Interactive startup hangs indefinitely (blank screen) when TERM_PROGRAM=Apple_Terminal (v2.1.237, macOS)
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 <pid> 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 <user> -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.
lsofshows nothing unusual; the blockingopenattarget could not be identified without root (lldb attach denied by hardened runtime; nofs_usagewithout 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:
[[ "$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.