[BUG] SessionStart hook env files (sessionstart-hook-N.sh) accumulate duplicate lines on re-run — never truncated; can escalate to null-byte Bash tool failure on Windows

Open 💬 0 comments Opened Jun 10, 2026 by marcusquiroga

Environment

  • Claude Code version: 2.1.170 (also observed on 2.1.167–2.1.169)
  • OS: Windows 11 (hooks run via Git Bash / MSYS2)
  • Reproducible: yes, persistent across versions

Description

Hooks that append to $CLAUDE_ENV_FILE (the documented API for persisting env vars from SessionStart hooks) write correctly. However, Claude Code never clears/truncates the per-session env files (~/.claude/session-env/<session-id>/sessionstart-hook-N.sh) when SessionStart hooks re-run within the same session (resume, /clear, compact, etc.). Each re-run appends the same lines again, so the file accumulates duplicates without bound.

Evidence

Scanned all 322 ~/.claude/session-env/<session-id>/ directories on one machine:

  • 38 files contain duplicated lines (sessions from 2026-05-12 through 2026-06-10)
  • Worst case: the same export line repeated 13× in a single sessionstart-hook-N.sh
  • Reproduced today on 2.1.170: two sessions show 2× duplicates from a marketplace plugin's SessionStart hook that has no idempotency guard

Example of an affected file (sanitized):

export MY_PLUGIN_DATA='C:/Users/<user>/.claude/plugins/data/<plugin>'
export MY_PLUGIN_SESSION_ID='<session-id>'
export MY_PLUGIN_DATA='C:/Users/<user>/.claude/plugins/data/<plugin>'
export MY_PLUGIN_SESSION_ID='<session-id>'
... (repeated up to 13×)

Impact

The accumulated content is prepended to every Bash tool invocation's preamble. In a severe case observed on 2.1.167 (12×+ accumulation across multiple hooks), Node.js spawn() failed with:

The argument 'args[2]' must be a string without null bytes. Received "export TEMP='...'..."

After that point the Bash tool was 100% unusable for the rest of the session (every invocation failed). The null bytes appear to be introduced when the oversized accumulated preamble goes through the Windows UTF-16→UTF-8 conversion path.

Expected behavior

sessionstart-hook-N.sh files should be truncated (or deduplicated) each time the corresponding SessionStart hook runs — re-running a hook should replace its prior contribution, not append to it.

Workaround

Plugin authors can add an idempotency guard before writing:

if ! grep -q "^MY_FLAG=" "${CLAUDE_ENV_FILE:-/dev/null}" 2>/dev/null; then
  echo "MY_FLAG=1" >> "${CLAUDE_ENV_FILE:-/dev/null}" || true
fi

This works, but every plugin author shouldn't need to know this — and third-party plugin hooks without the guard still pollute the session (which is how the duplicates keep appearing on 2.1.170).

View original on GitHub ↗