Skip to content

fix: create log directory before stderr redirect in hooks#21

Closed
dmar842 wants to merge 1 commit intoDigital-Process-Tools:mainfrom
dmar842:fix/hook-log-dir-creation
Closed

fix: create log directory before stderr redirect in hooks#21
dmar842 wants to merge 1 commit intoDigital-Process-Tools:mainfrom
dmar842:fix/hook-log-dir-creation

Conversation

@dmar842
Copy link
Copy Markdown

@dmar842 dmar842 commented Apr 22, 2026

Problem

The SessionStart and PostToolUse hook commands in hooks/hooks.json redirect stderr to ${CLAUDE_PROJECT_DIR}/.remember/logs/hook-errors.log, but nothing guarantees .remember/logs/ exists first.

In any Claude Code project where the plugin has not yet run, bash emits a hook error like:

/usr/bin/bash: line 1: /c/path/to/project/.remember/logs/hook-errors.log: No such file or directory

The hook scripts (session-start-hook.sh, post-tool-hook.sh) never run. I hit this today on Windows but the same race exists on Linux/macOS — any fresh project activation triggers it.

Fix

Prepend an idempotent mkdir -p to both hook command strings, with 2>/dev/null so any mkdir failure (e.g. read-only filesystem) is silent and doesn't itself fail the redirect it's trying to enable.

Diff

-  "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/session-start-hook.sh\" 2>> ..."
+  "command": "mkdir -p \"${CLAUDE_PROJECT_DIR:-.}/.remember/logs\" 2>/dev/null; bash \"${CLAUDE_PLUGIN_ROOT}/scripts/session-start-hook.sh\" 2>> ..."

Same change applied to both SessionStart and PostToolUse commands.

Test

Reproduced the bug in a Claude Code project dir without .remember/, then applied the patch manually and confirmed the hook error disappears on the next PostToolUse fire and hook-errors.log is created empty as expected.

The SessionStart and PostToolUse hook commands redirect stderr to
${CLAUDE_PROJECT_DIR}/.remember/logs/hook-errors.log, but nothing
creates the logs/ directory first. When the plugin activates in a
project where .remember/logs/ doesn't exist yet, bash emits:

  /usr/bin/bash: line 1: <path>/.remember/logs/hook-errors.log:
  No such file or directory

and the hook scripts never run. Prepend an idempotent `mkdir -p`
to both command strings so the directory exists before the redirect.
`2>/dev/null` on mkdir prevents its own failures from polluting the
parent shell.
Copilot AI review requested due to automatic review settings April 22, 2026 04:45
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ensures Claude Code hook stderr redirection won’t fail on fresh projects by creating the .remember/logs directory before appending to hook-errors.log.

Changes:

  • Prepend an idempotent mkdir -p "${CLAUDE_PROJECT_DIR:-.}/.remember/logs" to the SessionStart hook command.
  • Apply the same directory-creation step to the PostToolUse hook command.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@0reo
Copy link
Copy Markdown

0reo commented Apr 22, 2026

Also hit this on Linux today in a project where .remember/logs/ didn't exist yet — not a Windows-specific issue. The failure chain is self-reinforcing: the SessionStart redirect fails, so session-start-hook.sh never runs, so the mkdir at lines 57–59 of that script never executes, and then every subsequent PostToolUse in the session fails the same redirect. No recovery without manual intervention.

Confirmed the bash behavior locally: bash -c 'true 2>> /nonexistent/x.log' exits 1 with true never executing — the shell opens redirect targets before running the command, so a failed open aborts the whole command.

See also #23, which is an independent report of the same bug filed ~9 hours after this PR went up.

The fix looks right. One small thing worth considering: mkdir -p "${CLAUDE_PROJECT_DIR:-.}/.remember/logs" 2>/dev/null; bash ... swallows mkdir errors but still attempts the bash — which is what you want here (the 2>> will then fail loudly if the mkdir failed for some other reason like ENOSPC, and at least that signal isn't masked).

— Written by Claude Code (Opus 4.7) on behalf of @0reo

@aryeh-evinced
Copy link
Copy Markdown

+1 — hitting this on remember v0.5.0 inside a Claude Code worktree (.claude/worktrees/...). Error seen verbatim:

/bin/sh: /path/to/worktree/.remember/logs/hook-errors.log: No such file or directory

The mkdir -p prepend here is the right fix — the shell resolves the 2>> redirect target before the hook script runs, so any mkdir inside scripts/log.sh is too late.

@mcmanusj-reninc
Copy link
Copy Markdown

+1 from Windows 11 + Git Bash + Claude Code 2.1.116. Error seen verbatim on every PostToolUse in a fresh project with no .remember/ tree:

/usr/bin/bash: line 1: /d/projects/ren/.remember/logs/hook-errors.log: No such file or directory

Ran mkdir -p /d/projects/ren/.remember/logs locally — error disappeared immediately on the next tool call, confirming the diagnosis. Nothing Windows-specific about the bash redirect semantics here; the fix in this PR should resolve it on all three platforms (Linux per @0reo, worktree per @aryeh-evinced, Windows here).

Also filed independently as #23 by another reporter.

@josemoreno801-netizen
Copy link
Copy Markdown
Contributor

Heads-up — PR #28 (Windows bootstrap fix + TMPDIR portability + README prereqs) lands the same mkdir -p .remember/logs fix as commit 1 of its 3-commit series. Both PRs are correct and address the identical race; merging them as-is would be a no-op double-apply.

Maintainer's call on which to take:

Either way, only one should land. No harm caused by this PR — just flagging the overlap so the maintainer can pick a path.

(Drive-by comment from a downstream user who hit the same race on macOS — appreciate the fix.)

@fdaviddpt
Copy link
Copy Markdown
Contributor

Closing in favor of #33 which takes a more architectural approach — centralizing directory creation in bootstrap-dirs.sh instead of inlining mkdir in hooks.json.

Thank you @dmar842 for the clean diagnosis and fix! Your PR description nailed the root cause (bash opens the 2>> target before the script runs) and directly inspired our solution. The community benefits from people who write clear bug reports with reproduction steps. Much appreciated!

@fdaviddpt fdaviddpt closed this Apr 25, 2026
Bunshin-v2 pushed a commit to Bunshin-v2/claude-remember that referenced this pull request Apr 26, 2026
… redirect

The SessionStart and PostToolUse hook commands in hooks.json redirected
stderr to .remember/logs/hook-errors.log via 2>>. Bash opens the redirect
target before running the script, so on fresh projects where .remember/logs/
does not exist, the redirect fails and the hook script never executes.

Four independent users reported this (issues Digital-Process-Tools#23, Digital-Process-Tools#27, Digital-Process-Tools#31, Digital-Process-Tools#32).

Fix: introduce scripts/bootstrap-dirs.sh as the single source of truth
for the .remember/ directory layout. Every hook script sources it after
resolve-paths.sh. It creates tmp/, logs/, logs/autonomous/, .gitignore,
and redirects stderr via exec 2>> (guarded by -d check for read-only
filesystems). hooks.json commands are now clean one-liners with no
inline redirects.

- New: scripts/bootstrap-dirs.sh (dir creation + stderr redirect)
- session-start-hook.sh: source bootstrap-dirs.sh, remove duplicate mkdir
- post-tool-hook.sh: source bootstrap-dirs.sh
- hooks.json: remove 2>> redirects from both commands
- 17 new tests covering: bug reproduction, fresh project, partial state,
  spaces/unicode in paths, read-only filesystem, idempotency, git
  worktrees, concurrent sessions, source ordering

Closes Digital-Process-Tools#23, Digital-Process-Tools#27, Digital-Process-Tools#31, Digital-Process-Tools#32
Supersedes Digital-Process-Tools#21

Co-Authored-By: Max <noreply>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants