[Windows] SessionStart hooks cause infinite hang during initialization

Status Fixed / completed
Maintainer reply None cached
Activity 7 comments · opened Oct 14, 2025 · closed Dec 30, 2025

Environment

  • OS: Windows 10/11
  • Claude Code Version: Latest (as of 2025-10-14)
  • Node.js Version: Any
  • Hook Type: SessionStart with matchers
  • Platform Comparison: macOS ✅ Works | Linux ✅ Works (assumed) | Windows ❌ Hangs

Problem Description

SessionStart hooks cause Claude Code to become completely unresponsive on Windows during initialization. The hook subprocess executes and exits successfully, but Claude Code never detects the completion and hangs indefinitely. This requires force-closing the terminal to recover.

Root Cause Analysis

After extensive investigation, I've identified this as a Windows-specific subprocess lifecycle management bug in Claude Code's initialization phase:

The Deadlock Mechanism

┌─ Claude Code Initialization (Windows) ─┐
│ 1. Start synchronous initialization    │
│ 2. Spawn SessionStart hook subprocess  │
│ 3. **BLOCK** waiting for completion    │ ← Stuck here forever
│ 4. Enter event loop (NEVER REACHED)    │
└────────────────────────────────────────┘
         ↓
┌─ Hook Subprocess ───────────────────────┐
│ 1. Execute code                         │
│ 2. process.exit(0) successfully         │
│ 3. Send exit signal to parent           │
└─────────────────────────────────────────┘
         ↓
┌─ Parent Process ────────────────────────┐
│ ❌ Still in sync initialization block  │
│ ❌ NOT polling subprocess status       │
│ ❌ Exit signal queued but unprocessed  │
└─────────────────────────────────────────┘

Why Windows is Different

Unix/Linux/macOS: Async signals (kqueue/epoll) delivered even during blocking → hooks work ✅

Windows: Requires active polling of subprocess handles → sync init doesn't poll → signals never processed ❌

Minimal Reproduction

session-start-minimal.js:

// Literally just exit - no logic, no I/O
console.log('Starting');
process.exit(0);

settings.json:

{
  "hooks": {
    "SessionStart": [{
      "matchers": ["*"],
      "hooks": [{
        "type": "command",
        "command": "node session-start-minimal.js",
        "timeout": 5000
      }]
    }]
  }
}

Steps:

  1. Save files above
  2. Run claude in any directory
  3. Result: Infinite hang, cannot type prompts, Ctrl+C doesn't work

Critical Discovery

Even a hook that ONLY calls process.exit(0) with zero logic still hangs. This proves:

  • ❌ NOT a hook code issue
  • ❌ NOT a timeout issue
  • ❌ NOT a cleanup issue
  • ✅ IS a subprocess invocation issue during initialization

Failed Solution Attempts

Tried 5 different approaches:

  1. Force process.exit() - Hook exits, parent still hangs
  2. Wrapper functions - Same result
  3. Batch file wrapper - Parent waits for wrapper AND children
  4. PowerShell Start-Process - Job objects prevent true detachment
  5. File-based trigger - Even 10ms hooks cause hang

None work because Windows requires active polling, and sync init doesn't poll.

Why UserPromptSubmit/SessionEnd Work

These hooks execute AFTER initialization when:

  • Event loop is running
  • Parent actively polls subprocess status
  • Exit signals are properly detected

Impact

  • Severity: Critical - Complete feature loss for Windows users
  • Affected Users: All Windows users with SessionStart hooks
  • Workaround: Disable SessionStart, use UserPromptSubmit instead

Requested Fix

Option 1 (Recommended): Move SessionStart hooks to async initialization phase (after event loop starts)

Option 2: Add active subprocess polling during sync init on Windows

Option 3: Add timeout enforcement with force-kill

Option 4: Document limitation and skip SessionStart on Windows

Additional Context

This is a platform-specific issue that cannot be fixed at the hook level and requires changes to Claude Code's subprocess management on Windows.

View original on GitHub ↗

7 Comments

doobidoo · 10 months ago

Related Project Issue

This issue was discovered while implementing memory-aware session hooks for the MCP Memory Service project.

Related Issue: https://github.com/doobidoo/mcp-memory-service/issues/160

The project issue contains:

  • Full investigation timeline
  • Community discussion
  • Additional context about memory service integration
  • User impact on Windows developers using MCP Memory Service

Both issues are tracking the same bug from different perspectives:

  • This issue: Focus on Claude Code core fix
  • Project issue #160: Focus on workarounds and user guidance for MCP Memory Service users
joegoldin · 10 months ago

Just noting you can unblock and continue to use claude-code by pressing Enter/Return twice, as per https://github.com/anthropics/claude-code/issues/7755#issuecomment-3303271284

ianbuitrago-taulia · 10 months ago

I see this too when I send a prompt at the exact same time claude finishes if I have a stop hook enabled.

github-actions[bot] · 8 months ago

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.

doobidoo · 8 months ago

✅ Confirmed Fixed in Claude Code 2.0.76

Test Environment:

  • Windows 11
  • Claude Code version: 2.0.76
  • Node.js v22.19.0

Test Methodology:

  1. Created a minimal SessionStart hook that only logs and exits - worked fine
  2. Then tested a full-featured SessionStart hook (1100+ lines) with:
  • HTTP requests to memory service
  • Git repository analysis
  • File system operations
  • Complex async operations
  • 20-second timeout

Result:Both hooks execute correctly without hanging

The subprocess lifecycle management issue appears to be resolved in Claude Code 2.0.76. SessionStart hooks with matchers: ["*"] now work correctly on Windows.

Configuration that now works:

{
  "hooks": {
    "SessionStart": [{
      "matchers": ["*"],
      "hooks": [{
        "type": "command",
        "command": "node C:\path\to\session-start.js",
        "timeout": 20
      }]
    }]
  }
}

Thank you for the fix! 🎉

doobidoo · 8 months ago

Closing as fixed in Claude Code 2.0.76. SessionStart hooks now work correctly on Windows.

github-actions[bot] · 7 months ago

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.