[BUG] Terminal left in raw mode after CTRL+D exit

Resolved 💬 4 comments Opened Mar 26, 2026 by jayofdoom Closed Mar 26, 2026

Terminal left in raw mode after CTRL+D exit

Bug Description

Exiting claude-code via CTRL+D (EOF) leaves the terminal in raw mode. After exit, control sequences are printed literally (e.g. ^C, ^D) instead of being interpreted by the shell. The terminal is non-functional until manually reset.

Steps to Reproduce

  1. Note terminal state: stty -g > /tmp/stty-before
  2. Launch claude
  3. Press CTRL+D to exit
  4. Observe broken terminal — control characters print literally
  5. Capture broken state: stty -g > /tmp/stty-after (typed blind)
  6. diff /tmp/stty-before /tmp/stty-after confirms raw mode settings persist

Expected Behavior

Terminal is restored to its prior state on exit, regardless of exit method (CTRL+D, /exit, CTRL+C).

Actual Behavior

Terminal is left in a corrupted state. stty sane does not fix it — only reset (which sends RIS / \x1Bc) recovers the terminal. This indicates the problem is not limited to stty line discipline settings; terminal emulator state is also left dirty. Likely culprits:

  • Bracketed paste mode left enabled (\x1B[?2004h)
  • Focus reporting left enabled (\x1B[?1004h)
  • Possibly other DEC private modes

Root Cause

The CTRL+D (EOF) code path appears to exit the process before Ink's React unmount lifecycle completes. Ink's cleanup — which calls process.stdin.setRawMode(false) and writes \x1B[?2004l to disable bracketed paste — never executes.

Both the kernel terminal driver state (raw mode) and the terminal emulator state (DEC private modes) need to be restored. A process.on('exit', ...) handler should unconditionally:

  1. Call process.stdin.setRawMode(false)
  2. Write reset sequences to stdout (\x1B[?2004l, \x1B[?1004l, etc.)

Workaround

# Wrapper function — must restore both stty state AND terminal emulator state
claude() {
    local saved
    saved=$(stty -g)
    command claude "$@"
    stty "$saved"
    printf '\x1b[?2004l\x1b[?1004l'
}

Environment

  • Claude Code version: 2.1.84
  • OS: Gentoo Linux (amd64)
  • Kernel: 6.x (custom, AMD X870)
  • Terminal: foot
  • Shell: bash + starship prompt
  • Installation method: Binary package (Gentoo ebuild)

Related Issues

  • #12483 — Terminal state corruption after CTRL+Z suspension (same root cause, different signal)
  • #3355 — Raw mode persists after /memory command with vim
  • #31557 — Broken terminal state on exit (Windows)

All were closed by the inactivity bot without resolution.

View original on GitHub ↗

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