[BUG] 2-4 second delay on exit (Ctrl-C / /exit) due to sequential FSEvents watcher cleanup

Resolved 💬 7 comments Opened Jan 20, 2026 by adamtaylor13 Closed Mar 1, 2026

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?

Summary

Claude Code CLI takes 2-4 seconds to exit after Ctrl-C or /exit command. Profiling reveals the delay is caused by sequential closure of FSEvents file watchers, with each watcher blocking on a semaphore.

Environment

  • Claude Code version: 2.1.12 (npm-local install)
  • Platform: macOS 15.6.1 (Darwin 24.6.0)
  • Architecture: Apple Silicon (ARM64)
  • Node.js: v23.x
  • Terminal: iTerm2 / Terminal.app (same behavior in both)

Symptoms

  • Every exit (Ctrl-C or /exit) takes 2-4 seconds of hang time before returning to shell
  • No visible output during the delay
  • Delay occurs even with:
  • No MCP servers configured
  • Empty ~/.claude/todos/ and ~/.claude/debug/ directories
  • Minimal session activity
  • Increased heap size (--max-old-space-size=16384)
  • Network disconnected

Diagnostic Process

Ruled out the following potential causes:

  1. MCP server shutdown (disabled all MCP servers)
  2. Large config file / stale entries (cleaned up .claude.json)
  3. GC pressure (increased heap size - no change)
  4. iTerm2 shell integration (same in vanilla Terminal.app)
  5. Network teardown (same behavior offline)
  6. Large history.jsonl (moved file - no change)
  7. Accumulated todos/debug files (1720 + 1014 files moved - no change)

Root Cause

Used macOS sample command to capture stack traces during exit:

sample <pid> 10 -f /tmp/claude-exit-sample.txt

93% of samples (2575/2770) were blocked in FSEvents cleanup:

2575 Builtins_ArrayForEach
  2575 Builtins_CallApiCallbackGeneric
    2575 node::HandleWrap::Close
      2575 uv_close
        2575 uv_fs_event_stop
          2575 uv__fsevents_close
            2575 uv_sem_wait
              2575 semaphore_wait_trap  <-- BLOCKED HERE

The issue is that Claude Code:

  1. Creates many FSEvents watchers (for config files, skill directories, settings, etc.)
  2. On exit, iterates through watchers with Array.forEach
  3. Closes each watcher sequentially
  4. Each uv__fsevents_close call blocks waiting on a semaphore

This is a known limitation of libuv's FSEvents implementation on macOS - closing watchers involves thread synchronization that can be slow.

Suggested Fix

Options to consider:

  1. Close watchers in parallel rather than sequentially with forEach
  2. Reduce number of watchers - consolidate watched directories where possible
  3. Use a timeout - force exit after brief cleanup attempt rather than waiting for all watchers
  4. Lazy watcher cleanup - let the OS clean up on process termination for non-critical watchers

Sample Output (excerpt)

Full sample file available on request. Key section showing the hot path:

Call graph:
    2770 Thread_327367281   DispatchQueue_1: com.apple.main-thread  (serial)
    + 2770 start  (in dyld) + 6076
    +   2770 node::Start(int, char**)
    +     2770 node::NodeMainInstance::Run()
    +       2770 node::SpinEventLoopInternal(node::Environment*)
    +         2765 uv_run
    +           2589 uv__io_poll
    +             2588 uv__stream_io
    +               [... callback chain ...]
    +                 2575 Builtins_ArrayForEach
    +                   2575 node::HandleWrap::Close
    +                     2575 uv_close
    +                       2575 uv_fs_event_stop
    +                         2575 uv__fsevents_close
    +                           2575 uv_sem_wait
    +                             2575 semaphore_wait_trap

Workaround

None currently known. The delay is consistent regardless of configuration changes.

What Should Happen?

Ideally, hitting Ctrl-C should immediately close the application. Currently I have to wait for several seconds to move on to my next task.

Error Messages/Logs

Steps to Reproduce

See above

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.12

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

See above for comprehensive report direct from El Claude himself.

View original on GitHub ↗

This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗