Interactive mode exits immediately when no git repository is found

Resolved 💬 3 comments Opened Mar 7, 2026 by yskho Closed Mar 16, 2026

Environment

  • Claude Code version: 2.1.71 (also reproduced on 2.1.70)
  • Installation method: native (compiled ELF binary)
  • OS: Rocky Linux 8.9 (kernel 4.18.0-513.9.1.el8_9.x86_64)
  • glibc: 2.28-251.el8_10.25
  • API backend: Amazon Bedrock (CLAUDE_CODE_USE_BEDROCK=1)
  • Terminal: SSH via Windows PowerShell OpenSSH client
  • TERM: xterm-256color

Description

Claude Code interactive mode (TUI) exits immediately with exit code 0 when launched from a directory that is not part of any git repository. The UI renders completely (welcome screen, REPL prompt), but the process exits before accepting any keyboard input. Non-interactive mode (claude -p "...") works correctly regardless of git repository presence.

Steps to Reproduce

  1. SSH into a Linux server
  2. Ensure the current directory and all parent directories have no .git directory:

``bash
git rev-parse --git-dir 2>&1
# Should output: fatal: not a git repository
``

  1. Run claude (interactive mode)
  2. The TUI renders but the process exits immediately back to the shell prompt

Expected Behavior

Claude Code should start in interactive mode and accept keyboard input, even when no git repository is found in the current directory or its parents.

Actual Behavior

  • The TUI renders completely (welcome box, model info, REPL prompt with "Try ..." placeholder)
  • The process exits immediately with exit code 0
  • No error message is displayed
  • No debug log is written to ~/.claude/debug/
  • claude -p "hello" works correctly in the same directory

Workaround

Initialize a git repository in the working directory or any parent directory:

git init
claude  # Now works correctly

Root Cause Analysis (via strace)

Detailed strace analysis revealed the following:

1. Terminal raw mode is set up successfully

ioctl(0, TCSETSW, {B9600 opost -isig -icanon -echo ...}) = 0

2. stdin (fd 0) is never registered with epoll

$ grep "read(0" strace_read.log
# (empty - no read syscalls on fd 0)

stdin is never added to the epoll set, so the event loop never monitors for keyboard input.

3. Event loop exits immediately

$ grep -c "epoll_wait" strace_main.log
0

The Node.js event loop finds no active handles to wait on and exits. All epoll_pwait calls (observed in a -f trace) use timeout=0 (non-blocking), find no events, and the process proceeds to cleanup:

# Terminal settings restored to normal
ioctl(0, TCSETS, {B9600 opost isig icanon echo ...}) = 0
# Clean exit
exit_group(0)

4. Confirmed not a system/TTY issue

A Python script that sets stdin to raw mode and reads input works perfectly on the affected server:

import sys, tty, termios
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
    tty.setraw(fd)
    ch = sys.stdin.read(1)  # Successfully reads keypress
    print("Got: " + repr(ch))
finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, old)

Differential Analysis

The bug was identified by comparing two identical servers:

| Factor | Server A (working) | Server B (broken) |
|--------|-------------------|-------------------|
| ~/.git exists | Yes | No |
| Kernel | 4.18.0-513.9.1.el8_9 | 4.18.0-513.9.1.el8_9 |
| glibc | 2.28-251.el8_10.25 | 2.28-251.el8_10.25 |
| Binary MD5 | 9c4eedf2411a18eef6a08e94866bdff3 | 9c4eedf2411a18eef6a08e94866bdff3 |
| SELinux | Disabled | Disabled |
| SSH client | Windows PowerShell | Windows PowerShell |
| claude -p | Works | Works |
| claude (interactive) | Works | Exits immediately |

Server A had a git repository initialized in the home directory (~/.git), so every subdirectory was under git. Server B had no git repository in ~/ or its parents. Initializing a git repo on Server B (git init) immediately resolved the issue.

Additional Notes

  • The same binary (identical MD5 checksum) exhibits different behavior based solely on git repository presence
  • The bug was also confirmed with version 2.1.70
  • A completely fresh Claude Code configuration (removing ~/.claude/ and ~/.claude.json) did not resolve the issue
  • Running inside GNU Screen or with Python's pty.spawn() did not resolve the issue
  • The trust dialog prompt (shown before REPL) accepts keyboard input normally; only the REPL input fails

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗