CLAUDE_ENV_FILE: session ID mismatch on resume causes env files to be written to wrong directory
Description
When resuming a session (--continue, /resume, or context compaction), CLAUDE_ENV_FILE points to a startup session's directory, but the env file loading function (ybI() in the compiled binary) reads from the resumed session's directory. This means environment variables written by SessionStart hooks are never found.
Steps to Reproduce
- Register a project SessionStart hook that writes to
CLAUDE_ENV_FILE:
``bash``
#!/bin/bash
INPUT=$(cat)
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export MY_TEST_VAR="hello"' >> "$CLAUDE_ENV_FILE"
fi
exit 0
- Start Claude Code interactively, then use
/resumeor--continueto resume the session
- In the resumed session, run:
````
echo $MY_TEST_VAR
- Expected:
hello - Actual: Variable is unset
Root Cause
Verified by analyzing the compiled binary's JavaScript source (strings /path/to/claude):
At hook execution time (SessionStart), R$() returns the startup session ID (a transient session created before the resume completes). The CLAUDE_ENV_FILE path is generated as:
~/.config/claude/session-env/STARTUP_SESSION_ID/sessionstart-hook-N.sh
At Bash tool execution time, R$() returns the resumed session ID. The env loader (ybI()) reads from:
~/.config/claude/session-env/RESUMED_SESSION_ID/
Since these are different directories, the env files are never found.
Evidence
Debug hooks logging CLAUDE_ENV_FILE and stdin JSON during SessionStart:
# Startup SessionStart (source: "startup")
CLAUDE_ENV_FILE=~/.config/claude/session-env/21a1c086-.../sessionstart-hook-0.sh
stdin: {"session_id":"21a1c086-...","source":"startup"}
# Resume SessionStart (source: "resume")
CLAUDE_ENV_FILE=~/.config/claude/session-env/21a1c086-.../sessionstart-hook-0.sh ← SAME startup dir
stdin: {"session_id":"8b55bdb2-...","source":"resume"} ← DIFFERENT session ID
Then in Bash tool calls, ybI() looks in session-env/8b55bdb2-.../ which is empty.
Confirmed working on fresh sessions: Pre-seeding session-env/SESSION_ID/sessionstart-hook-0.sh and running claude --session-id SESSION_ID correctly sources the env file. The loading mechanism works — only the session ID mismatch on resume is broken.
Confirmed broken on resume: Writing to the startup session's directory (where hooks actually write) and verifying the resumed session can't find those files.
Additional Note
There is also a caching issue: ybI() caches its result after the first call. If the first call happens before env files exist, it caches null and never re-checks. The cache is only invalidated on compaction/SessionStart events via RbI(). This is a secondary concern but compounds the primary session ID mismatch.
Environment
- Claude Code 2.1.38
- Linux (WSL2)
- Hooks registered in
.claude/settings.json(project level)
Related Issues
- #15840 — CLAUDE_ENV_FILE empty string (different bug, may be fixed for project hooks)
- #11649 — CLAUDE_ENV_FILE not passed to plugin hooks (fixed)
- #12418 — CLAUDE_ENV_FILE not sourced on resume (closed as duplicate of #11649, but this is a separate root cause)
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗