[BUG] Freezes terminal most of the time when trying to access anything remotely related to tty devices.
Resolved 💬 24 comments Opened Aug 21, 2025 by kimasplund Closed Mar 3, 2026
● Bash(stty -F /dev/ttyACM0 -a 2>/dev/null | head -5)
⎿ speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
-> freeze...
● Bash(sudo screen -L -Logfile c6_serial.log /dev/ttyACM0 115200 &)...
-> freeze...
ok that also freezes you. try just to access any tty device and see if you freeze
● Let me test with a simpler TTY device to confirm the issue:
● Bash(ls -la /dev/tty /dev/tty0 /dev/pts/0 2>/dev/null | head -3)
⎿ crw------- 1 kim tty 136, 0 Aug 20 12:24 /dev/pts/0
crw-rw-rw- 1 root tty 5, 0 Aug 21 11:18 /dev/tty
crw------- 1 root tty 4, 0 Aug 20 12:23 /dev/tty0
✶ Whisking… (esc to interrupt)
-> freeze...
24 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
I just raised a new issue that does look like a variant of this one, so I'll close mine and add the details here
---
Environment
Bug Description
While using the Bash tool to run tests that interact with hardware, both the hardware and Claude Code lock up and nee to be forcefully killed.
I'm using Cluade Code to build a hardware interfacing library; which boils down to sending ascii data to an embedded device (which is running micropython) over USB CDC (serial / tty), the device processes that data then sends a response back up the usb cdc to the host.
There's hardware tests in this library which Claude Clode has been running as part of the development cycle, (implement, build, test, etc) which had been working great, however more and more recently the device was getting locked up and Claude Code was also getting locked up, usually during a Bash tool use that was relating to the tty device under test.
The exact same tests scripts run directly from ssh/bash run just fine for 100's of cycles, however when Claude Code run the same script it usually locks up within one or two iterations.
When I say locked up, I mean text input no longer works and even the little anthoropic logo ticker that flickers while active, freezes.
At this point ctrl-c / escape doesn't have any impact. It will stay this way for hours if I leave it. I generally have to kill the tmux session and/or switch to a different terminal to pkill the claude instance.
While in this locked up state, I can connect to the hardware device with a separate terminal all (normally mpremote) but it too would appear unresponsive to all normal commands. I was able to confirm via a hardware debugger though that the target processor itself appeared to be running normally, it was running through it's normal main / repl loop still.
I've now discovered that unplugging the usb device generally unfreezes claude code.
Similarly, without unplugging the device I've found that I can use lsof to find the open handle to the serial device then use gdb to forcefully close that handle from within the claude program - this unblocks the hardware and allows the terminal/mpremote to communicate with it normally again.
<details>
<summary>Click to expand details</summary>
``` bash
$ sudo lsof | grep ttyACM0
claude 826926 corona 24r CHR 166,0 0t0 3554 /dev/ttyACM0
claude 826926 826927 node corona 24r CHR 166,0 0t0 3554 /dev/ttyACM0
claude 826926 826928 node corona 24r CHR 166,0 0t0 3554 /dev/ttyACM0
claude 826926 826929 node corona 24r CHR 166,0 0t0 3554 /dev/ttyACM0
claude 826926 826934 node corona 24r CHR 166,0 0t0 3554 /dev/ttyACM0
claude 826926 826935 node corona 24r CHR 166,0 0t0 3554 /dev/ttyACM0
claude 826926 826936 node corona 24r CHR 166,0 0t0 3554 /dev/ttyACM0
mpremote 839011 corona 3uW CHR 166,0 0t0 3554 /dev/ttyACM0
$ sudo gdb -p 826926
...
For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 826926
(gdb) call close(24)
$1 = 0
(gdb) detach
Detaching from program: /home/corona/.nvm/versions/node/v22.16.0/bin/node, process 826926
[Inferior 1 (process 826926) detached]
(gdb) exit
I have also been running into what sounds like the exact same issue. I am trying to get claude code to write a serial driver for a nordic development board, and python pytests to test its functionality.
Regardless of whether I am using the board's Jlink serial port or a separate FTDI cable, claude code will invariably freeze up within one or two interactions of the serial port device. Interestingly it seems to happen even if claude is not directly interacting with the port, eg running a python script to read from it. As with andrewleech, replugging the port frees up claude, but it will normally freeze up again shortly after.
While frozen, the working animation ascii thing stops, I cannot type, cannot ctrl c - nothing works. The moment I unplug the offending usb port, it continues where it left off. I am running on a laptop with debian installed, the issue happens if I run in the local terminal or ssh'ing into the laptop.
Its a shame, it renders claude code unusable for this sort of embedded work at the moment.
+1 Hangs when trying to access the serial port through bash or Python.
One pseudo-workaround is to run CC in WSL, then have it write Python to be run from PowerShell.
I'm thinking I should try an older version but haven't quite figured out just how old I'll need to go
workaround I found handy: using
firejail --private-dev claudeand asking claude to run stuff through sshshamefully, i opened this dupe but hopefully eases the pain
Ah yes, that's an (annoying) great idea. Similarly can probably use a docker container and/or separate computer and still tell claude to execute everything via ssh!
In case it helps; when I use gdb to forcefully close the ttyACM0 file handle in the claude executable, claude crashes :-) this is the stack trace:
It's still crashing on the latest calude, but not _every_ time it accesses a tty. So I'm still making decent progress with claude development that access hardware, but when it locks up I just need to kill the claude process, then
claude -cand say eitheror if I don't want to to lock up again from re-running the same thing I'll run the locking up test manually and paste it into claude ie
/dev/serial/by-id/usb-MicroPython_Pyboard_Virtual_Comm_Port_in_FS_Mode_34003000-if00
✅ WB55 works with only base address fix!
To simplify killing just the claude that's stuck on a tty I got this basic script written:
~/kill-tty-process.sh``` bash
#!/bin/bash
Get processes with open handles to ttyACM devices
processes=$(sudo lsof 2>/dev/null | grep '/dev/ttyACM' | awk '{print $2}' | sort -u)
if [ -z "$processes" ]; then
echo "No processes found with open ttyACM handles"
exit 0
fi
process_count=$(echo "$processes" | wc -l)
if [ "$process_count" -eq 1 ]; then
pid="$processes"
echo "Found single process $pid with open ttyACM handle, killing..."
kill -9 "$pid"
echo "Process $pid killed"
else
echo "Multiple processes found with open ttyACM handles:"
sudo lsof 2>/dev/null | grep '/dev/ttyACM' | awk '{print $1, $2, $9}' | sort -k2,2n
fi
I improved your script to kill multiple session
It also kill hanging process in USB and cuaU.
This bug is pretty annoying especially when you code speak about a modem or device, and claude want to check it really connected. boom => stuck.
User:
I've now found the serial port issue is in the claude executable after it tries to open a /dev/ttyX port file as per this stack trace:
Assistant Response:
The crash is caused by
claudeusingfs.readFileSyncon a TTY device. When Node.js reads a TTY character device, the file descriptor can enter a state whereuv_fs_closefails to close it, triggering the assertion failure.This is the exact TTY lockup scenario described in the safety protocol. The issue is:
readFileSyncatnode:fs:442:20opens/dev/ttyXuv_fs_closenode_file.cc:2606The CLI should not be directly reading TTY devices with synchronous file operations. If it needs to interact with serial devices, it should either:
serialport)socatwrapper pattern for TTY accessYou may want to report this as a bug at https://github.com/anthropics/claude-code/issues - the CLI appears to be scanning or reading files without filtering out character devices.
As an immediate workaround, you could use your new script to kill the stuck process before it gets to the crash point, or restrict the CLI's access to
/dev/tty*devices.---
Solution Request
User:
the issue has already been raised and I have been using the script to kill the app when it happens, but that slows down progress. would it be possible to add a runtime monkey patch or modify an intermediate library or even node internal function to forcefully filter out / block calls of readFileSync when the target is a tty device?
Assistant Response:
I'll investigate the feasibility of intercepting
readFileSynccalls to TTY devices. Let me explore the options.[Investigated Claude CLI structure and found it's a large bundled JavaScript file]
I can see the CLI is a large bundled JavaScript file. Based on the stack trace and the TTY safety protocol, I can create a runtime monkey patch to intercept
fs.readFileSynccalls before they reach TTY devices.Solution: Node.js Preload Module
I'll create:
tty-protect.js) that monkey-patchesfs.readFileSyncclaude-safe) that loads the protection before launching the CLIThe monkey patch will:
fs.readFileSynccalls/dev/tty*Implementation Details:
tty-protect.js:
fs.readFileSyncandfs.readSyncfs.statSyncto check if target is a character device/dev/ttyAND is a character deviceclaude-safe wrapper:
NODE_OPTIONS=--requireto inject the monkey patchThis approach:
Implementation Plan:
tty-protect.jspreload module that monkey-patchesfs.readFileSyncandfs.readSyncto detect and block character device reads on/dev/tty*pathsclaude-safewrapper script that loads the protection module via NODE_OPTIONS before launching the CLIThe protection will intercept TTY device reads before they cause the Node.js assertion failure, while allowing all other file operations to work normally.
---
Implementation Phase
Assistant Actions:
Created File 1:
~/tty-protect.jsNode.js preload module that:
fs.readFileSyncandfs.readSyncfunctionsisTTYDevice()function that:/dev/ttyfs.statSyncto verify it's a character devicefs.readFileSyncto:isTTYDevice()on the target pathfs.readSync(primarily protected at readFileSync level)Key Features:
/dev/ttyCreated File 2:
~/claude-safeBash wrapper script that:
NODE_OPTIONSto preload the protection moduleexec nodeFeatures:
NODE_OPTIONSif setexecfor proper process replacementUsage Instructions
To use the protected CLI:
!claude-tty-safe.zip
---
Summary: With the above runtime patch I think the problem is "resolved" in that I have not have any further lockups in the last day or so with hardware in the loop testing! I do see some exception stack trace printouts on the claude code screen occasionally, every time it tries to talk to a tty port, but claude code seems to keep working like normal no worries. The stack traces are not in the conversation feed, the kind of print over the top but then disappear once I continue the conversion - they don't seem to even interrupt the actual claude workings.
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.
I've had the problem re-occur in the last few days when I ran without my hack/patch above.
+1 I've had 3 sessions freeze up on me the last few days. Running on macOS Tahoe, using wezterm and fish shell.
Happening here - arch linux (btw), zsh, urxvt. Trying to do stuff with ttyUSB1
Also happening for me...
Fedora, Bash/Zsh
this also happens very frequently but not 100% of the time while developing a hid driver, claude keeps opening
/dev/hidrawNblocking itself. I am suspecting this is some kind of pre-emptive read of either files written to by the subprocess or file paths printed by the subprocess to either monitor for filechanges and inform the agent or drive the code rollback feature.I'll leave my Claude's findings here for whomever might find it useful:
Root Cause Found
After bash execution, the code at line 454711 (beautified source) calls
ctB()which uses Haiku LLM to extract file paths from stdout. These paths are then passed toM5.call()(the Read tool) at line 454720.If paths like
/dev/hidraw0or/dev/ttyACM0appear in bash output, they get passed toreadFileSync()→ FREEZEThe problematic code flow:
Fix (inject before the M5.call):
Source locations (in beautified cli.js):
ctB()function: line 281759 - uses Haiku to extract file paths from bash outputM5.call(): line 454720 - calls the Read tool on extracted pathsM5= Read tool (var X3 = "Read"at line 170375)W9= "Bash" tool name (line 163084)Z9= Bash tool definition (line 454535)Patch Script
I created a patch script that fixes this issue by modifying the installed CLI:
Gist: https://gist.github.com/heeen/b6ced51aeac9da1b315776f38752c4ff
How it works
The script uses Babel to parse the minified
cli.js, finds the code pattern where file paths extracted from bash output are passed to the Read tool, and injects a check to skip/dev/*paths.Usage
The patch adds this check before the
M5.call()(Read tool):This prevents Claude from trying to
readFileSync()on device files like/dev/hidraw0or/dev/ttyACM0that appear in bash output.@heeen I'm not sure if you saw my runtime patch above in https://github.com/anthropics/claude-code/issues/6237#issuecomment-3393668561 I've been using it for a few months and it's been working well. Not sure if it covers hid as well though. It looks like yours is more targetted though, have you had any further lock-ups while running it?
I liked the deployment of @andrewleech 's fix, but it doesn't work with the new native Claude Code as it uses NODE_OPTIONS preload modules. Have updated it to use LD_PRELOAD, it hasn't crashed for me yet but I've one just started using it today.
Same deployment, I put it in ~/.local/bin, give it
chmod +xand then just runclaude-safeinstead ofclaude. You'll want gcc installed. Only tested on Linux, should work on MacOS I'd think.claude-tty-safe-v0.2.0.zip
Edit: Updated to fix error with LD_PRELOAD being inherited into child processes such as gcc and causing trouble
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
It seems like this has gotten better/fixed? I haven't had it hang on tty access recently.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.