[BUG] Claude Code spawned ~3,000 parallel bash processes in 17 seconds, causing OOM crash and hard reboot.
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?
Claude Code spawns thousands of bash subprocesses in parallel within seconds, exhausting all system memory and triggering the kernel OOM killer. This has occurred multiple times.
~3,079 bash processes were spawned between PID 21300 and PID 24379 in approximately 17 seconds (12:38:41–12:38:58 local time). All processes were owned by UID 1000, all carried oom_score_adj:100 (set by Claude Code). The code process itself reached ~1.4 TB virtual memory allocation. Usually this results in a total lock up of the host and requires a full reboot.
What Should Happen?
Bash subprocesses are spawned sequentially or with a reasonable concurrency limit that respects system memory.
Error Messages/Logs
Kernel OOM log evidence (journalctl -b -1 -k --no-pager | grep -A 50 "Out of memory"):
Mai 25 12:38:41 <hostname> kernel: Out of memory: Killed process 5301 (code) total-vm:1463373852kB, anon-rss:200640kB, file-rss:2916kB, shmem-rss:2076kB, UID:1000 pgtables:2096kB oom_score_adj:300
Mai 25 12:38:57 <hostname> kernel: [ 21300] 1000 21300 61965 2732 2285 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21301] 1000 21301 61313 2468 2023 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21303] 1000 21303 61967 2673 2226 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21304] 1000 21304 61313 2475 2030 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21305] 1000 21305 61967 2705 2258 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21306] 1000 21306 61314 2444 1999 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21307] 1000 21307 61314 2477 2032 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21308] 1000 21308 62001 2646 2199 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21309] 1000 21309 61315 2445 2000 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21310] 1000 21310 62001 2710 2263 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21311] 1000 21311 61315 2513 2036 477 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21312] 1000 21312 61316 2482 2037 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21313] 1000 21313 62002 2654 2207 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21314] 1000 21314 61316 2485 2040 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21315] 1000 21315 62002 2718 2271 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21316] 1000 21316 61317 2454 2009 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21317] 1000 21317 61318 2490 2045 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21318] 1000 21318 62003 2687 2240 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21319] 1000 21319 61319 2458 2013 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21320] 1000 21320 62003 2751 2304 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21321] 1000 21321 61319 2527 2082 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21322] 1000 21322 62004 2659 2212 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21323] 1000 21323 61320 2464 2019 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21324] 1000 21324 61320 2500 2055 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21325] 1000 21325 62004 2723 2276 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21326] 1000 21326 61321 2468 2023 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21327] 1000 21327 62006 2663 2216 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21328] 1000 21328 61321 2536 2091 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21329] 1000 21329 62006 2727 2280 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21330] 1000 21330 61322 2504 2059 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21331] 1000 21331 61322 2508 2063 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21332] 1000 21332 62007 2669 2222 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21333] 1000 21333 61323 2509 2032 477 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21334] 1000 21334 62007 2733 2286 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21335] 1000 21335 61358 2513 2068 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21336] 1000 21336 61358 2513 2068 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21337] 1000 21337 62008 2673 2226 447 0 90112 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21338] 1000 21338 61359 2521 2076 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21339] 1000 21339 62008 2737 2290 447 0 90112 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21340] 1000 21340 61359 2489 2044 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21341] 1000 21341 61360 2522 2077 445 0 77824 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21342] 1000 21342 62009 2677 2230 447 0 94208 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21343] 1000 21343 61360 2491 2046 445 0 77824 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21344] 1000 21344 62009 2773 2326 447 0 94208 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21345] 1000 21345 61361 2559 2114 445 0 81920 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21346] 1000 21346 62010 2682 2235 447 0 94208 1888 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21347] 1000 21347 61361 2495 2050 445 0 81920 1408 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21348] 1000 21348 61362 2531 2086 445 0 81920 1376 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21349] 1000 21349 62010 2778 2331 447 0 94208 1824 100 bash
Mai 25 12:38:57 <hostname> kernel: [ 21350] 1000 21350 61362 2500 2055 445 0 81920 1408 100 bash
--
Mai 25 12:38:58 <hostname> kernel: Out of memory: Killed process 13836 (Web Content) total-vm:2821064kB, anon-rss:7324kB, file-rss:3604kB, shmem-rss:1216kB, UID:1000 pgtables:580kB oom_score_adj:233
Steps to Reproduce
Fresh install of claude code, no changes in any settings.
This happens specifically when claude decides to read files or use the find command.
Having extracted a bash command that previously caused an issue, I can reproduce the issue by entering the prompt:
"run this bash command: find /Path/ -maxdepth 3 -type f \( -name ".tex" -name ".makefile" -o -name "Makefile" \) 2>/dev/null | head -30 && echo "---" && find /Path/-maxdepth 3 -type d | head -20)"
Where /Path/ is a working path and manual execution of the bash command works.
System info
- OS: Fedora 42
- Kernel: 6.19.14-101.fc42.x86_64
- RAM: 32 GB
- Shell: fish
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.150 (Claude Code)
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
Showing cached comments. Read the full discussion on GitHub ↗
11 Comments
lol
This is not a repo contains claude-code source code
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
The 3,000-bash-in-17-seconds pattern is the OS-level manifestation of what's been documented in the May 2026 sub-agent failure cluster as "scope expansion via uncapped parallel dispatch" — the same primitive that causes the silent-stall and dispatch-fabrication patterns also enables runaway concurrency when the model decides to fan out.
Three signals from your kernel log narrow the cause:
oom_score_adj:100set by Claude Code on every spawned bash — this is intentional, Claude Code marks its spawned subprocesses so the OOM killer picks them over the parent. But at 3,079 processes, the marker is overwhelmed; the killer hits the parent (code) first because the parent's VSZ is 1.4 TB.sleep, nowait, noxargs -P N. The parent is callingspawn/execin a tight loop. The likely call site is the Bash tool with a single command that internally fans out (e.g.,find ... -exec bash -c '...' \;or a loop the model generated without bounds).Operator-side mitigations (working today):
A. Wrap bash through ulimit + cgroup. The cleanest layer to enforce concurrency is the kernel. Run Claude Code under a systemd-run scope with
MemoryMax=4GandTasksMax=200:When the limit is hit, the cgroup OOM killer takes only Claude Code's tree, not the entire host. Your hard reboot becomes a graceful
claudeexit.B. PreToolUse hook to reject bash fan-out patterns. Add a hook that scans Bash tool calls for fan-out signatures (
for,while,find.*-exec,xargs(?! -P [0-9]),parallel) and either blocks them or rewrites them to bounded forms (e.g., inject| xargs -P 8 -n 1). cc-safe-setup shipsexamples/bash-fanout-bounded-rewriter.shfor this — it converts unbounded loops to boundedxargs -Pinvocations or refuses the call.C. PostToolUse hook to count subprocesses. After every Bash tool call, count immediate children of
claude. If the count exceeds N (default 50), terminate the session before the next tool call. This is the "circuit breaker" approach — useless after the fact when the host has already rebooted, but the previous two layers should prevent reaching this state.Why this isn't already default in Claude Code:
The Bash tool surface explicitly trusts the model's concurrency judgment, because a meaningful fraction of legitimate workloads (test parallelism, build steps, batch file processing) require it. A blanket TasksMax in Claude Code itself would break those workflows. The cgroup-based mitigation (A) is the right architectural answer because it lets each operator pick their bound at the OS level rather than the application level.
This is one of the cases I cover in the Sub-Agent Observability Handbook Chapter 5 (scope expansion sub-pattern) — your case is the most extreme production example of the pattern (3,079 spawns vs the previously documented worst case of ~150).
cc-safe-setup hook collection: https://github.com/yurukusa/cc-safe-setup
Thanks for the input, approach A definitely provided an effective safeguard against a total system lock up. However, it also essentially rendered the bash tool useless in these situations; this is a response after executing the aforementioned command again: "The system is under resource pressure (fork failures). Try running the command again in a moment, or check if there are too many processes running. You can try ! find ... in the prompt, or wait a bit and retry."
I was not able to locate the script you mentioned in your repo, and initial efforts of my own in using a pre tool hook to try to catch this behaviour has been unsuccessful thus far.
@fdpr-H — thank you for testing Approach A in practice and reporting back. Your observation is exactly right, and your instinct to look for the PreToolUse hook layer is the correct architectural answer. However, I owe you a correction: when I referenced
examples/bash-fanout-bounded-rewriter.shin my earlier comment, that script did not actually exist in the repo yet. That was a claim-verify gap on my side — the exact failure shape I've spent the last month writing about. I apologize for the misdirection that made you spend time searching.It exists now. I shipped it today in PR #440, MIT, 172 lines + 47 tests:
Install:
Wire up in
~/.claude/settings.json:Detection signatures (7 patterns, ordered most-severe-first):
find ... -exec— the worst case, shell-spawning per resultfor ... in $(...)/for ... in */for ... in $VAR— dynamic-list loopswhile read .../while IFS=...— unbounded per-line loopsparallelwithout-j N— defaults to one-per-coremake -jwithout N — defaults to infiniteseq N | while/for/xargswhere N > 100 — high-cardinalityxargs without
-Pdeliberately passes through because serial xargs is safe (one process at a time). The hook only refuses when the pattern can spawn N>1 concurrent processes.On detection: exits 2 with a stderr advisory that names the matched pattern, shows a bounded rewrite of the same command, and provides the override path. The rewrite for your kind of case (
find . -exec ...) is the standardfind ... -print0 | xargs -0 -P 8 -n 1 <cmd>form — same workload, capped at 8 concurrent processes, sustainable on every workstation tested.Override knobs (in env):
CC_BASH_FANOUT_DISABLE=1— turn the whole hook off (operator already aware)CC_BASH_FANOUT_OVERRIDE=1— allow one specific call (clear after the call to re-arm)CC_BASH_FANOUT_PARALLEL_BOUND=N— change the suggested rewrite's N (default 8)Why this layer instead of cgroup TasksMax alone: Approach A blocks ALL bash including light single-process calls under pressure, which is exactly what you saw. This hook intercepts only the fan-out shape, so
ls,git status, simplerm, etc. keep working at full speed. Approach A remains the right backstop (the kernel-level catch-all for misses), but Approach B handles the common case without making bash useless when the OOM killer is hovering.I've left the original
find ... -execadvisory referencing this hook in PR #440's commit message, so the trace is in the record. If you find the detection list misses a pattern from your environment, file a thin issue againstyurukusa/cc-safe-setupand I'll add it — the matrix is public and easy to extend.Also: the case-study deepens the Cluster 1 (Sub-Agent Observability) chapter on scope expansion. Your 3,079-spawn event is now the canonical extreme example I cite when explaining why operator-side concurrency caps matter, alongside the 12-hour silent stall (#61405) and the 120GB recommend-as-authorization case (#61102). Thanks for documenting it so cleanly.
Same here on Windows (Claude Code v2.1.156, Opus 4.8): an ultracode workflow's
subagents kept spawning nested local PowerShell processes until they piled up,
maxed out RAM, and crashed my machine along with two other Claude Code windows I
had open.
@allenfu000 — thanks for the cross-platform data point. Your Windows reproduction confirms that the failure mode is platform-independent at the root, but the trigger differs from @fdpr-H's original case in a way that matters for the mitigation surface.
Two distinct triggers, one root failure
Your reproduction and @fdpr-H's both end in unbounded subprocess spawn → OOM, but they enter the failure through different paths:
find ... -exec, one unbounded loop, or oneparallelwithout-j). The fan-out happens inside a tool call the model issued.This second pattern is the nested-spawn sub-pattern of Cluster 1 (Sub-Agent Observability) — uncapped fan-out at the orchestration layer rather than inside a single tool call — and the operator-side hooks for it are structurally different from the bash-fan-out hook. Three implications:
bash-fanout-bounded-rewriter.shfrom PR #440 will not catch your case. It hooksPreToolUseonBash, scans the command string for fan-out signatures (find -exec,for/while,parallel,xargswithout-P). PowerShell tool calls and Task/SendMessage subagent dispatches don't match its scope by design.PreToolUseonTask/SendMessage— the dispatcher itself. A hook there can count active subagents per session and refuse to dispatch a new one when the count exceeds N, regardless of whether the subagents go on to spawn PowerShell, bash, or nothing at all. That's the right layer because it gates the fan-out before any subprocess work begins.systemd-runwithTasksMax) has no clean Windows analog. Windows' equivalent is Job Objects withJOB_OBJECT_LIMIT_ACTIVE_PROCESS. The PowerShellStart-Job/Start-Processpath doesn't compose with Job Objects as cleanly assystemd-runcomposes withbash, but the Windows Sandbox and WSL2's cgroup v2 both give you the same kind of kernel-enforced ceiling if you're willing to run Claude Code inside one of them.Operator-side mitigations that work today on Windows
A. Run Claude Code in WSL2 instead of native Windows. Then @fdpr-H's
systemd-run --user --scope -p MemoryMax=4G -p TasksMax=200 claudeworks unchanged. This is the lowest-effort fix if your tooling allows it. WSL2 was the platform where the originalbash-fanout-bounded-rewriter.shwas tested, and the hook itself is shell-agnostic at the command-string level (PowerShell tool calls don't trigger it, but bash calls inside WSL still do).B. Wrap Claude Code in a Windows Job Object on native Windows. Job Objects are the kernel-supported way to set a hard ceiling on a process tree's RAM and active-process count; when a limit is hit, the Job terminates the tree rather than damaging the host. The practical entry points are
procgov(open-source, MIT) or theJob ObjectWin32 API wrapped in PowerShell. I'd direct you to the procgov README for exact flag syntax rather than cite specifics from memory — the tool's documentation is the authoritative source on the supported limit categories (memory, process count, CPU rate). The architectural point is that if you wrap Claude Code in a Job Object with a process-count ceiling, the failing ultracode tree can't reach beyond its own job to take down your other Claude Code windows.C. Subagent-count
PreToolUsehook (not yet shipped, but the right architectural fix). A PowerShell-compatiblePreToolUsehook that:Task/SendMessagedispatch.tool_resultyet).CC_NESTED_SPAWN_BUDGET=Nenv var for legitimate parallel workloads.I've been treating this as a "design-stage" hook in the Cluster 4 work — your reproduction is the strongest case I've seen for shipping it sooner. Tracking it as PR target; if I can land it in the next 48h, I'll comment back here with the install path. I'm being deliberate about not promising the ship date — the architecture needs verification that the transcript-scan can keep up with high-frequency dispatches without becoming a bottleneck itself. (This is the same self-correction I owe @fdpr-H for the earlier
bash-fanout-bounded-rewriter.shclaim that didn't exist yet at the time I referenced it.)Why this is escalating in the May 2026 surge
Your "two other Claude Code windows" detail is the clue I want to flag for triage. In the original Linux case, the OOM killer's target heuristic (oom_score_adj on bash, parent's massive VSZ) limited collateral damage to the host's other processes. On Windows, the OOM behavior differs: Windows' memory manager will swap, then page-fault, then crash entire processes before reaching a stable state, and the cross-window damage you saw is consistent with virtual memory exhaustion affecting the whole user session before the trigger process itself dies.
This means the Windows failure is potentially worse than the Linux failure for users running multiple Claude Code sessions — a single rogue ultracode workflow can take down concurrent productive sessions. The Cluster 4 surface deserves its own mitigation layer rather than relying on platform-level catches.
I'll add your case to the cluster-tracker as the canonical Windows + ultracode example, alongside @fdpr-H's case as the canonical Linux + single-bash-fanout example, in the next docs commit. The tracker is at yurukusa.github.io/cc-safe-setup/cluster-tracker.html — the nested-spawn pattern lives under Cluster 1 (Sub-Agent Observability) rather than having its own cluster slot. I'll link the docs PR in a follow-up once it lands.
Thanks again for the precision in the report — "two other Claude Code windows" is exactly the kind of detail that makes the cross-platform severity legible.
@allenfu000 — follow-up on the subagent-count
PreToolUsehook commitment from my earlier comment. It shipped today (PR #474, MIT, 158 lines + 26 tests passing).Install
Wire into
~/.claude/settings.json:What it does
PreToolUseon the three dispatcher tool names (Task,Agent,SendMessage).transcript_pathfrom the hook payload), not a counter file. Scans the trailing 2000 lines (configurable viaCC_NESTED_SPAWN_LOOKBACK).tool_useentries whosenameis in the dispatcher family. Subtracts any with a matchingtool_result. The remaining set is the in-flight ids.CC_NESTED_SPAWN_BUDGET(default 5), exits 2 with a stderr advisory naming the count, the budget, the in-flight ids, and the override path. Otherwise exits 0.Why this design instead of a counter
The cc-safe-setup catalog already had
max-concurrent-agents.shandsubagent-budget-guard.sh— both increment a counter on dispatch. The dual error mode (over-counts on rebound, under-counts on burst recovery) is structural to the approach, because there's no clean decrement signal. The transcript-based variant doesn't have that problem because the actual in-flight state is reconstructed from the source of truth (the transcript) on every dispatch. As a bonus, it matches both the modern (Task/SendMessage) and legacy (Agent) tool names; the counter-file variants only matchAgent.Override knobs
For your specific ultracode case (where the workflow legitimately needs more than 5 concurrent subagents):
CC_NESTED_SPAWN_BUDGET=N— raise the ceiling globally. Recommended: tune based on your actual observed concurrency cap (start at 5, raise if the hook fires during workloads you trust).CC_NESTED_SPAWN_OVERRIDE=1— one-shot bypass for a specific dispatch. Clears after the next call.CC_NESTED_SPAWN_DISABLE=1— kill switch. Set when you're debugging the hook itself.What it does NOT solve
bash-fanout-bounded-rewriterto catch fan-out inside a single PowerShell tool call is still missing. It's the natural next ship; the matrix structure is the same, the detection signatures need to be translated to PowerShell idiom (ForEach-Object -Parallel,Start-Job,Invoke-Commandagainst multiple computers, etc.). I'm flagging it as a tracked gap; if you want to file a thin issue againstyurukusa/cc-safe-setupdescribing the PowerShell patterns you observed, that would prioritize the matrix work directly.The kernel-level backstop still matters
The hook is the application-level catch. The architectural point from my earlier comment stands: wrap Claude Code in a Windows Job Object (via
procgovor the Win32 API) with a process-count ceiling, so even if the hook misses or a future bug bypasses it, the failing tree can't reach beyond its own job to take down other Claude Code windows. The hook prevents the common case efficiently without making bash useless under pressure; the Job Object catches the misses.Thanks again for the precision in the report — the "two other Claude Code windows" detail was what made the cross-platform severity legible, and it's what motivated shipping this hook on the same day rather than rolling it into the next sprint.
@allenfu000 — short follow-up to round out the Windows-specific surface I owed you context on. Published today (MIT, ~1,735 words):
→ Claude Code on Windows — Safety Guide for the Issues That Don't Exist on macOS/Linux
It articulates five Windows-specific failure modes from the May 2026 tracker (BSOD with HVCI, the nested-PowerShell cascade case you reported, empty Bash output on Win11, PowerShell unavailable under MINGW64, OAuth paste freeze) and a "WSL2 vs native Windows" decision tree. Section 2 cites your reproduction as the canonical Windows case for the cross-window crash failure mode, alongside @fdpr-H's Linux case.
The cc-safe-setup README now links to the guide from its existing Windows Support section (PR #475, merged today), so other Windows operators landing on the repo can find the guidance without having to dig through issue threads.
I deliberately listed the cc-safe-setup Windows coverage gaps explicitly — PowerShell-specific fan-out detection (the PowerShell equivalent of
bash-fanout-bounded-rewriter.sh), Windows Job Object integration to automate the procgov wrap, HVCI compatibility detection at SessionStart. These are tracked as future work; if you hit a PowerShell fan-out pattern that the guide should name, a thin issue againstyurukusa/cc-safe-setupwould help prioritize.Closes the loop on the commitment from my earlier comment in this thread. Thanks again for the precision in your original report — the "two other Claude Code windows" detail was the operational signal that made the cross-platform severity worth writing up.
I solved it, and must admit, this one is on me.
First step was to collect some more detailed data, I used a simple bash script to save the output of
psinto a file.I noticed that the processes were not individually spawn by claude but rather all seemed to be child processes of the first one.
Ultimately the root cause was a malformed line in my
.bashrcwhich causedPATHto get overwritten with a useless literal string, so the shell could no longer find any command.With
PATHbroken, the Fedoracommand_not_found_handle function, invoked whenever a command isn't found, runs$(gettext …)in its non-interactive branch. Butgettextitself is now unfindable, so the handler recursively triggers itself, and because each call forks a command-substitution subshell, it becomes a fork bomb. (The recursing subshells inherit the original argv, which is why ps shows an infinite chain of identical bash -c -l … processes.)