claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[Bug] Claude drops keystrokes when editing prompts in external editor

Open aliou opened this issue 1 month ago • 6 comments

Bug Description When using Ctrl+G to open Neovim to edit the prompt, every few keystrokes is dropped and not correctly included in the prompt. This has been occurring since the move to the bun binary and wasn't happening with the node package. Running npx to launch Claude doesn't have the issue either.

Environment Info

  • Platform: darwin
  • Terminal: ghostty
  • Version: 2.0.37
  • Feedback ID:

Errors

[{"error":"Error\n    at Kw (/$bunfs/root/claude:59:1142)\n    at <anonymous> (/$bunfs/root/claude:64:10074)\n    at emit (node:events:92:22)\n    at endReadableNT (internal:streams/readable:861:50)\n    at processTicksAndRejections (native:7:39)\n    at spawnSync (unknown)\n    at spawnSync (node:child_process:226:22)\n    at execSync (node:child_process:275:109)\n    at T (/$bunfs/root/claude:1312:1602)\n    at kMD (/$bunfs/root/claude:1312:1780)\n    at request (/$bunfs/root/claude:66:2146)\n    at processTicksAndRejections (native:7:39)\n    at spawnSync (unknown)\n    at spawnSync (node:child_process:226:22)\n    at execSync (node:child_process:275:109)\n    at T (/$bunfs/root/claude:1312:1602)\n    at kMD (/$bunfs/root/claude:1312:1780)\n    at SMD (/$bunfs/root/claude:1312:2309)\n    at SMD (/$bunfs/root/claude:1312:2432)\n    at A (/$bunfs/root/claude:11:15230)","timestamp":"2025-11-11T10:22:39.912Z"},{"error":"Error\n    at Kw (/$bunfs/root/claude:59:1142)\n    at <anonymous> (/$bunfs/root/claude:64:10074)\n    at emit (node:events:92:22)\n    at endReadableNT (internal:streams/readable:861:50)\n    at processTicksAndRejections (native:7:39)\n    at request (/$bunfs/root/claude:66:2146)\n    at processTicksAndRejections (native:7:39)","timestamp":"2025-11-11T10:22:50.567Z"}]

aliou avatar Nov 11 '25 10:11 aliou

it's getting very annoying, somehow I can't even exit nvim occasionally.

EDIT: It's been like this a couple versions back. I thought someone would file an issue or the CC Team would discover it and fix it. But it's still here. version 2.0.37

jackielii avatar Nov 11 '25 11:11 jackielii

Same issue (2.0.37) — makes external editor unusable

jojule avatar Nov 13 '25 19:11 jojule

Having the same problem with brew install. Switched to npm install as @aliou mentioned. Now my neovim feels fast and does not skip keypresses.

antosha417 avatar Nov 14 '25 09:11 antosha417

Detailed Root Cause Analysis with Diagnostic Evidence

I can confirm this issue on Linux with Claude Code 2.0.34 and 2.0.42 (native/Bun installation). The issue persists in the latest native release (2.0.42). Through extensive debugging with strace, I've identified the exact root cause.

The Problem: Bun Busy-Polling Stdin While Editor Runs

The native Claude Code binary (embedded Bun 1.3.1 runtime) continues reading from stdin in non-blocking mode after spawning the editor, creating a race condition where both processes compete for keystrokes.

Diagnostic Evidence

  1. Both Claude and the editor share the same terminal:
$ sudo ls -la /proc/$(pgrep claude)/fd/16
lr-x------ /proc/3298853/fd/16 -> /dev/pts/2

$ sudo lsof -p $(pgrep vi) | grep pts
vi   3301846   x   0u   CHR  136,2   /dev/pts/2
vi   3301846   x   1u   CHR  136,2   /dev/pts/2
vi   3301846   x   2u   CHR  136,2   /dev/pts/2

Both processes are using the same /dev/pts/2 terminal instead of Claude creating a separate PTY for the editor.

  1. Claude has a 60% read error rate while the editor is running:
$ sudo strace -p $(pgrep claude) -e trace=read -c
# (traced for ~10 seconds while typing in vi)

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 98.86    0.000692           1       386       230 read

230 EAGAIN errors out of 386 read attempts (60% error rate) - Claude/Bun is busy-polling stdin continuously.

  1. Continuous non-blocking read attempts on fd 16 (/dev/pts/2):
$ sudo strace -p $(pgrep claude) -e trace=read -tt 2>&1 | grep EAGAIN | head -10
14:48:39.226412 read(16, ..., 262143) = -1 EAGAIN (Resource temporarily unavailable)
14:48:39.252950 read(16, ..., 262074) = -1 EAGAIN (Resource temporarily unavailable)
14:48:40.074311 read(16, ..., 262144) = -1 EAGAIN (Resource temporarily unavailable)
14:48:40.306133 read(16, ..., 262144) = -1 EAGAIN (Resource temporarily unavailable)
# ... continues constantly at ~30-50ms intervals
  1. The editor itself has no issues:
$ sudo strace -p $(pgrep vi) -e trace=read,write,ioctl -c
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 64.86    0.000048           1        36           read
 33.78    0.000025           0        48           write
------ ----------- ----------- --------- --------- ----------------
100.00    0.000074           0        85           total

Zero errors - the editor is functioning properly, it's the Claude process interfering.

What's Happening

When a keystroke arrives at /dev/pts/2:

  • If Claude's non-blocking read() executes first → keystroke consumed by Claude, editor never sees it (dropped input)
  • If editor reads first → Claude gets EAGAIN (wasted CPU cycle, but no data loss)

The 60% EAGAIN error rate shows Claude is constantly polling and competing with the editor for input.

Bun Version and Related Issue

Claude Code 2.0.34 native binary uses Bun v1.3.1:

$ strings /path/to/claude/bin/claude | grep "Bun v"
Bun v1.3.1 (Linux x64 baseline)
Bun v1.3.1 (89fa0f34) Linux x64 (baseline)

This appears related to https://github.com/oven-sh/bun/issues/10694 which was supposedly fixed in Bun 1.3.0, but the fix may be incomplete or Claude Code's usage pattern still triggers the issue.

From that Bun issue:

"Bun would not correctly release a readline instance and so it would continue to grab characters from stdin even when other things (i.e. the nvim subprocess) are also reading input."

Workaround Confirmed

As reported by multiple users above, installing via npm/pnpm (which uses Node.js runtime instead of Bun) completely resolves the issue:

npm install -g @anthropic-ai/claude-code
# or
pnpm install -g @anthropic-ai/claude-code

This confirms the issue is specific to the Bun runtime.

Environment Details

  • Claude Code Version: 2.0.34 and 2.0.42 (native installation with Bun 1.3.1)
  • OS: Linux (kernel 6.17.3)
  • Terminals tested: Ghostty, Alacritty (issue occurs in both)
  • Editors tested: nvim, vi --clean (issue occurs with all editors)
  • Multiplexer: Tested with and without tmux (issue persists in both cases)

Note: Issue confirmed to persist in the latest native release (2.0.42).

Suggested Fix

Since Claude Code is already using Bun 1.3.1 (which supposedly fixed the readline issue), the problem likely lies in how Claude Code is using readline:

  1. Ensure Claude properly closes/releases readline before spawning the editor - Most likely fix. The Bun issue claims to be fixed in 1.3.0, but Claude is still experiencing it in 1.3.1, suggesting Claude's code isn't properly releasing readline/stdin before spawning the child process.

  2. Create a proper PTY pair for the editor subprocess - More robust architectural fix. Instead of sharing the parent's terminal, create a PTY master/slave pair using openpty() or similar, giving the editor the slave side and having Claude communicate through the master side.

  3. Try updating to the latest Bun version - Least likely to help since Bun 1.3.1 already has the supposed fix, but worth trying if newer versions have additional improvements.

xav-ie avatar Nov 16 '25 20:11 xav-ie

I am us macOS Sonoma 14.6, latest Neovim, in kitty terminal. Same issue, neovim is nearly not usable. I am only able to use neovim for things that I cannot do in the claude code terminal but it is very difficult, you always have to backspace and fix stuff.

sittim avatar Nov 17 '25 15:11 sittim

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

github-actions[bot] avatar Dec 18 '25 10:12 github-actions[bot]