[BUG] Claude code race condition got into unrecoverable state
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
I typed a message just as claude finished a task. It then ignored that message but appeared to be running todos (ignoring my message), even though I could enter new messages still. I up arrowed and hit enter to reissue my message and then it got stuck flashing around (see screencast).
I can't interrupt with ^c, ^z or escape and will have to kill the process.
Claude is taking 123% CPU too:
972070 matthew 20 0 71.5g 811392 45364 R 123.8 5.2 9:09.74 claude
kill didn't kill it, I had to kill -9 it
https://github.com/user-attachments/assets/2f825a8d-129d-429a-a8a8-93329eb67a52
What Should Happen?
Should not get stuck.
Error Messages/Logs
> rglobbing the _entirety_ of a clojure installation sounds...scary
● You're absolutely right! That's way too aggressive. Let me think about this more carefully.
The clojure installer likely just creates a few wrapper scripts in bin/ that have embedded paths. We should be much more
targeted. Let me check what files the clojure installer actually creates:
● Bash(curl -sL https://github.com/clojure/brew-install/releases/download/1.12.3.1577/linux-install.sh | head -100)
⎿ #!/usr/bin/env bash
set -euo pipefail
… +56 lines (ctrl+o to expand)
● Perfect! I can see exactly what needs to be fixed. The clojure installer uses sed to embed paths into just two wrapper
scripts: bin/clojure and bin/clj.
So we need a much simpler, targeted fix - just update those two scripts. Let me revise:
● Update(bin/lib/installable/script.py)
⎿ Updated bin/lib/installable/script.py with 29 additions
10 from lib.staging import StagingDir
11
12
13 + def relocate_script_paths(source: str | Path, dest: str | Path) -> None:
14 + """
15 + Relocate paths in script-installed files from staging to final destination.
16 +
17 + Only processes text files in bin/ directory to avoid touching binaries or data files.
18 + """
19 + source_path = Path(source).absolute()
20 + dest_path = Path(dest).absolute()
21 +
22 + source_path_bytes = bytes(str(source_path), "utf-8")
23 + dest_path_bytes = bytes(str(dest_path), "utf-8")
24 +
25 + # Only process files in bin/ directory to be safe
26 + bin_dir = source_path / "bin"
27 + if not bin_dir.exists():
28 + return
29 +
30 + for file_path in bin_dir.iterdir():
31 + if file_path.is_file() and not file_path.is_symlink():
32 + try:
33 + content = file_path.read_bytes()
34 + if source_path_bytes in content:
35 + content = content.replace(source_path_bytes, dest_path_bytes)
36 + file_path.write_bytes(content)
37 + except (OSError, PermissionError):
38 + # Skip files we can't read/write
39 + continue
40 +
41 +
42 class ScriptInstallable(Installable):
43 def __init__(self, install_context: InstallationContext, config: dict[str, Any]):
44 super().__init__(install_context, config)
> and we _should not ignore errors_
● Good point! Let me fix the error handling:
● Update(bin/lib/installable/script.py)
⎿ Updated bin/lib/installable/script.py with 4 additions and 8 removals
29
30 for file_path in bin_dir.iterdir():
31 if file_path.is_file() and not file_path.is_symlink():
32 - try:
33 - content = file_path.read_bytes()
34 - if source_path_bytes in content:
35 - content = content.replace(source_path_bytes, dest_path_bytes)
36 - file_path.write_bytes(content)
37 - except (OSError, PermissionError):
38 - # Skip files we can't read/write
39 - continue
32 + content = file_path.read_bytes()
33 + if source_path_bytes in content:
34 + content = content.replace(source_path_bytes, dest_path_bytes)
35 + file_path.write_bytes(content)
36
37
38 class ScriptInstallable(Installable):
● Now let me update the install() method to use this relocation:
● Update(bin/lib/installable/script.py)
⎿ Updated bin/lib/installable/script.py with 2 additions and 1 removal
82 super().install()
83 with self.install_context.new_staging_dir() as staging:
84 self.stage(staging)
85 - self.install_context.move_from_staging(staging, self.name, self.install_path)
85 + relocate = relocate_script_paths if self.relocate_paths else None
86 + self.install_context.move_from_staging(staging, self.name, self.install_path,
+ relocate=relocate)
87 if self.install_path_symlink:
88 self.install_context.set_link(Path(self.install_path), self.install_path_symlink)
89
> this is now rather special cased
● You're right - adding a config flag makes this feel overly specific. How about we just always do this relocation for
ScriptInstallable?
The logic is safe:
- Only touches files in bin/ directory
- Only does string replacement if the staging path is found
- Errors will fail loudly
Since script installers typically create wrapper scripts that embed paths, this would be a sensible default behavior.
What do you think?
> Can we at least make the `bin` thing configuration (default to `bin` sure)
∴ Thinking…
· Adding relocation support to ScriptInstallable… (esc to interrupt · ctrl+t to hide todos)
⎿ ☐ Add relocation support to ScriptInstallable
☐ Update clojure.yaml to use relocation
☐ Test the clojure installation with relocation
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
>
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
bollo:infra (main) $
fish: Job 1, 'claude' terminated by signal SIGKILL (Forced quit)
Steps to Reproduce
unsure, I've not had it happen before
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.0.14
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
am in GNOME terminal.
Seems "racey" to me; the suspicious submitting Can we at least make the bin thing configuration (default to bin sure) just as it completed and apparently ignored my message...
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗