Skip to content

v2.1.23+ causes 100% CPU hang with multiple parallel instances and hooks #22172

Closed

Description

@Marcel-Bich

Description

Claude Code hangs with 100% CPU usage when running multiple parallel instances with hooks enabled. This regression was introduced somewhere between v2.1.22 and v2.1.23.

Environment

  • OS: Linux (WSL2, Ubuntu)
  • Claude Code version: 2.1.27 (also affects 2.1.25)
  • Installation: Native client (not npm)
  • Profile: Custom config directory via CLAUDE_CONFIG_DIR

Steps to Reproduce

  1. Enable hooks in settings (disableAllHooks: false)
  2. Have multiple plugins with hooks enabled (e.g., PreToolUse hooks for Bash, Write, Edit)
  3. Start 2+ Claude Code instances in parallel
  4. One or more instances will hang at 100% CPU

Expected Behavior

Multiple parallel instances should work without hanging, as they did in v2.1.22.

Actual Behavior

  • Instances hang with ~100% CPU usage
  • Even simple commands like /plugin cause hangs
  • The UI becomes unresponsive
  • Process must be killed with kill -9

Workaround

Using v2.1.22 resolves the issue completely:

CLAUDE_CONFIG_DIR=$HOME/.claude-work /path/to/versions/2.1.22

With v2.1.22, everything works perfectly - all hooks, all plugins, multiple parallel instances.

Potentially Related Changes

Looking at the changelog, these changes between 2.1.22 and 2.1.27 might be relevant:

  • v2.1.27: "Content-level ask now takes precedence over tool-level allow" - permission handling change
  • v2.1.23: "Fixed race condition causing 400 errors with prompt caching scope" - might have introduced new race conditions
  • v2.1.23: "Fixed per-user temp directory isolation on shared systems"

Hook Configuration

The hooks are standard PreToolUse/PostToolUse hooks that return JSON with permissionDecision. Example hook output:

{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}

Additional Context

  • The issue does NOT occur with v2.1.22 regardless how many sessions in parallel and regardless which hooks are enabled or disabled
  • CPU usage stays at around 90-100% until the process is manually killed
  • No error messages are displayed before the hang
  • The issue does occur on the first user prompt then it hangs completely

Activity

  1. github-actions commented on Jan 31, 2026

    @github-actions

    Found 3 possible duplicate issues:

    1. [BUG] Regression in 2.1.27: Infinite CPU loop on project startup #22057
    2. Session resume freezes with 100% CPU due to redundant progress events in session files #22149
    3. [BUG] Claude Code crashes with 100%+ CPU usage on ARM (v2.1.27) #22141

    This issue will be automatically closed as a duplicate in 3 days.

    • If your issue is a duplicate, please close it and 👍 the existing issue instead
    • To prevent auto-closure, add a comment or 👎 this comment

    🤖 Generated with Claude Code

  2. Marcel-Bich commented on Jan 31, 2026

    @Marcel-Bich
    Author

    Correction: Disabling hooks (disableAllHooks: true) does NOT fix the issue. The only confirmed workaround is downgrading to v2.1.22.

    This makes the issue more similar to #22158 - it appears to be a fundamental problem in v2.1.23+ rather than hook-specific.

  3. Denubis commented on Feb 1, 2026

    @Denubis

    It's still present in .29, and feels different than the .27 crashes from yesterday. It was hanging on pretooluse for me, but only on certain calls.

  4. edwinhu commented on Feb 2, 2026

    @edwinhu

    Subscribing - experiencing similar issues

  5. jcfischer commented on Feb 3, 2026

    @jcfischer

    same problems for me

  6. yurukusa commented on Mar 21, 2026

    @yurukusa

    I run Claude Code on WSL2 with 8 hooks (via npx cc-safe-setup) and haven't hit this CPU hang — but I typically run 1 instance, not multiple in parallel.

    Possible workaround for parallel instances:

    Ensure hooks use file locks to avoid concurrent execution conflicts:

    #!/bin/bash
    # Add at the top of each hook to prevent concurrent execution issues
    LOCK="/tmp/claude-hook-$(basename "$0").lock"
    exec 200>"$LOCK"
    flock -n 200 || exit 0  # Skip if another instance is running this hook

    Alternative — reduce hook execution for parallel sessions:

    Check if the hook is being called too frequently by logging timestamps:

    LAST="/tmp/claude-hook-last-$(basename "$0")"
    NOW=$(date +%s)
    PREV=$(cat "$LAST" 2>/dev/null || echo 0)
    echo "$NOW" > "$LAST"
    
    # Skip if last execution was less than 100ms ago
    if [ $((NOW - PREV)) -eq 0 ]; then
        exit 0  # Too frequent, skip
    fi

    The 100% CPU pattern suggests hooks are being spawned in a tight loop. File locking prevents the cascade.

  7. boshu2 commented on May 2, 2026

    @boshu2

    Adding macOS Apple Silicon evidence + quantitative scope to this thread, since this issue is framed Linux-WSL2 only but the failure mode appears identical on macOS.

    I filed #55609 earlier today for what I now believe is the same bug: 100% CPU hang on hook-configured claude after backgrounded-bash interrupt. The bot suggested this issue as a duplicate, and reading your repro, I agree.

    Two corrections vs the framing here:

    1. Single instance is enough. I don't need 2+ parallel claudes to reproduce — single claude session with any hook in ~/.claude/settings.json (SessionStart / SessionEnd / Stop / PreToolUse / PostToolUse) freezes on backgrounded-bash interrupt. ~60 second repro.
    2. Affects macOS Apple Silicon as severely as Linux, possibly more — on macOS the hang escalates to whole-userland stall (kernel rejects new fork() calls system-wide). Not just process-stuck, system-stuck.

    Quantitative scope from a freeze-capture monitor I had running this morning (08:32–12:05 PDT, ~3.5 hours active dev):

    • 21 distinct freeze events captured across 5 separate claude PIDs (28428, 42495, 47974, 55383, 99538)
    • System 1-min load average peaked at 18.99 during freezes, baseline 3.37 (5.6× idle)
    • The capture monitor itself hit fork: retry: Resource temporarily unavailable repeatedly while trying to spawn sample/vm_stat — kernel was system-wide out of process slots, not just claude stuck

    Stack trace from one stuck claude (PID 77747, 2026-05-02 08:27:44, claude 2.1.126, macOS 26.4.1):

    • 2,561 thread samples on com.apple.main-thread (serial)
    • All 2,561 in same call path: + 0x6569a0 → 0xe37c6c → 0x849910 → ...
    • Same syscall-loop signature as @smconner's Linux x86_64 gcore disassembly in #18532 — V8 JIT property-descriptor-hash-table loop

    I haven't downgraded to v2.1.22 yet but will test if it would help diagnosis. Also worth noting: the bot also flagged #52253 ("tree-kill dependency causes pgrep storm / 100% CPU when reaping Bash subprocess trees on macOS") as a duplicate — the tree-kill / pgrep angle in that title matches my stack trace exactly. Could be the same root cause as the regression introduced in 2.1.23.

    Forensic dir (7 freeze snapshots, 21-event log, sample profiles for 5 PIDs, vm_stat captures, fork-failure stdout) ready to share. Disclosure: I build AgentOps on top of Claude Code; filing as a daily user.

  8. boshu2 commented on May 2, 2026

    @boshu2

    Confirming this regression still reproduces on macOS in 2.1.126 (originally filed for Linux/WSL2 — bug is platform-agnostic). 4-step repro in #55609 triggers it deterministically; vanilla settings.json ({}) does not.

    System spindump caught the parent main-thread in a posix_spawn loop with kernel turnstile waits naming pgrep children — the tree-kill/Bg6 storm tracked in #52253. Forensic detail: #52253 comment.

  9. bcherny commented on Aug 19, 2026

    @bcherny
    Collaborator

    Tried to reproduce this on the current release (2.1.233) on Linux and couldn't.

    Setup matched the report: a custom CLAUDE_CONFIG_DIR, hooks enabled in settings (PreToolUse for Bash/Write/Edit returning {"permissionDecision":"allow"}, plus PostToolUse and UserPromptSubmit), two plugins each adding their own PreToolUse hooks, and 3 parallel interactive instances sharing that config dir.

    Observed: /plugin opened instantly, first prompts and multiple simultaneous tool-heavy turns completed in every instance, the hooks demonstrably applied (tools ran with no permission prompt), and CPU stayed at ~4–6% per instance throughout — no hang or spin.

    Several fixes for 100% CPU loops, freezes, and multi-instance races have shipped in recent releases since 2.1.27 (see the changelog), so this looks resolved in a recent release.

    Closing — if you still hit this on the latest version, please reply with your version, plugin list, and /doctor output and we'll reopen.

    🤖 Generated with Claude Code

  10. github-actions commented on Oct 9, 2026

    @github-actions

    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.

  11. locked as resolved and limited conversation to collaborators on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions