SessionStart hook setup fails with EEXIST mkdir on Windows when plugin data directory already exists

Resolved 💬 3 comments Opened May 1, 2026 by alsgur9865-sketch Closed May 5, 2026

Summary

On Windows, every session start prints multiple SessionStart:startup hook error messages caused by EEXIST: file already exists, mkdir ... when Claude Code tries to create per-plugin data directories that already exist. The same error pattern also breaks the built-in Bash tool's per-session env directory creation, blocking shell commands entirely once it triggers.

The plugin hooks themselves still appear to run, but the Bash tool failure is fully blocking — I literally could not file this issue from inside Claude Code because every gh invocation hit the same EEXIST.

Environment

  • OS: Windows 11 Home (10.0.26200)
  • Shell: Git Bash (also reproduced inside Claude Code's built-in Bash tool)
  • Claude Code: 2.1.119
  • Enabled plugins (relevant): claude-mem@thedotmack, superpowers@claude-plugins-official

Repro

  1. Enable claude-mem@thedotmack and superpowers@claude-plugins-official.
  2. Start a new Claude Code session in any project.
  3. Observe the session-start banner and try to invoke the Bash tool.

Actual

Four red error lines on session start:

SessionStart:startup hook error
  Failed to run: EEXIST: file already exists, mkdir 'C:\Users\<user>\.claude\plugins\data\claude-mem-thedotmack'
SessionStart:startup hook error
  Failed to run: EEXIST: file already exists, mkdir 'C:\Users\<user>\.claude\plugins\data\superpowers-claude-plugins-official'

Bash tool calls fail every time with:

EEXIST: file already exists, mkdir 'C:\Users\<user>\.claude\session-env\<uuid>'

The command never executes — the error is emitted before the user's shell command runs.

Expected

Directory creation should be idempotent. If the target directory already exists, setup should silently continue.

Suspected cause

A bare fs.mkdir(path) / fs.mkdirSync(path) call without { recursive: true }. On POSIX the equivalent is often mkdir -p, but on Windows the raw Node fs call surfaces EEXIST immediately and the wrapper treats it as fatal.

The error is emitted before each plugin's own hooks.json command runs, so this is in Claude Code's plugin data-directory bootstrap (and a separate occurrence in the Bash session-env bootstrap), not in third-party hook code.

Impact

  • Plugin SessionStart bootstrap: noisy but non-functional — hooks still execute.
  • Bash tool session-env bootstrap: fully blocking — no shell commands can run for the rest of the session.

Workarounds tried

  • Deleting the offending directories: error returns next session.
  • Disabling the plugins suppresses the SessionStart noise but doesn't fix the Bash session-env failure.

Suggested fix

Replace bare mkdir with fs.mkdir(path, { recursive: true }) (or wrap in a try/catch that ignores EEXIST) in:

  1. The plugin data-directory bootstrap (~/.claude/plugins/data/<plugin>-<marketplace>).
  2. The Bash tool session-env bootstrap (~/.claude/session-env/<uuid>).

View original on GitHub ↗

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