Skip to content

[BUG] UserPromptSubmit hook exits non-zero with no stderr when worker health check fails (missing || true) #2090

Description

@mikelkew

Before submitting

Related but not duplicates:


📝 Manual Bug Report

Bug Description

The UserPromptSubmit hook defined in plugin/hooks/hooks.json can exit with a non-zero status and zero bytes of stderr, producing the Claude Code error:

UserPromptSubmit hook error — Failed with non-blocking status code: No stderr output

The cause is in the shell command itself. The final step is:

[ "$_HEALTH" = "1" ] && node "$_R/scripts/bun-runner.js" "$_R/scripts/worker-service.cjs" hook claude-code session-init

There is no trailing || true. So whenever the worker's /health endpoint is not reachable within the 10×1s retry budget (worker restarting, cold start, transiently unhealthy, port mismatch, etc.), [ "$_HEALTH" = "1" ] evaluates to false, the whole shell command exits with status 1, and nothing is written to stderr. Claude Code surfaces it as the "No stderr output" error above.

Comparable branches in the same file (e.g. SessionStart session-init, which was hardened in #1794 via adding a || true / defensive echo ... || true) already guard against this. The UserPromptSubmit branch was not updated.

Checked all cached versions on the reporter's machine (12.1.5, 12.1.6, 12.2.0, 12.3.2, 12.3.7, 12.3.8, 12.3.9) and the command tail is byte-identical — the missing || true has been present since at least 12.1.5. The latest main on GitHub is also still affected.

Steps to Reproduce

  1. Install or run claude-mem@12.3.9 in Claude Code.
  2. Stop the worker (pkill -f worker-service.cjs) or otherwise make http://$HOST:$PORT/health unreachable.
  3. Submit any prompt.
  4. Claude Code shows: UserPromptSubmit hook error — Failed with non-blocking status code: No stderr output.

It also reproduces intermittently in normal use (right at session start, after a crash, or when the worker is briefly busy enough to miss the 10-second retry budget).

Expected Behavior

When the worker is unreachable, the hook should exit 0 silently — the same contract the SessionStart session-init branch now uses. The end user should never see a non-zero status from this hook just because the worker had not yet come up.

Proposed Fix

Append || true (or equivalent) to the UserPromptSubmit command in plugin/hooks/hooks.json. For example:

- … [ "$_HEALTH" = "1" ] && node "$_R/scripts/bun-runner.js" "$_R/scripts/worker-service.cjs" hook claude-code session-init
+ … [ "$_HEALTH" = "1" ] && node "$_R/scripts/bun-runner.js" "$_R/scripts/worker-service.cjs" hook claude-code session-init || true

A stricter variant that keeps the "only run node when healthy" guard but never leaks a non-zero exit:

if [ "$_HEALTH" = "1" ]; then
  node "$_R/scripts/bun-runner.js" "$_R/scripts/worker-service.cjs" hook claude-code session-init || true
fi
exit 0

Either way, the hook should match the graceful-degradation already applied to SessionStart in #1794.

Environment

  • Claude-mem version: 12.3.9 (latest, released 2026-04-22)
  • Claude Code version: 2.1.118
  • OS: macOS Darwin arm64
  • Platform: Claude Code (desktop/CLI)
  • Node: v24.14.1

Logs

Worker health confirmed functional when captured:

$ curl -sf http://127.0.0.1:<port>/health
{"status":"ok","timestamp":<ts>,"activeSessions":2}
EXIT=0

When the worker is up, the hook's own session-init runs cleanly and returns {} with exit 0:

$ _R="~/.claude/plugins/cache/thedotmack/claude-mem/12.3.9"
$ node "$_R/scripts/bun-runner.js" "$_R/scripts/worker-service.cjs" hook claude-code session-init
{}
EXIT=0

The failure is entirely in the outer shell command when _HEALTH=0 — no log entry is produced because nothing inside the node handler is reached.

One related WARN observed in ~/.claude-mem/logs/claude-mem-YYYY-MM-DD.log (may or may not relate):

[WARN ] [HOOK  ] session-init: No sessionId provided, skipping (Codex CLI or unknown platform)

This path already returns {continue:true, suppressOutput:true, exitCode: SUCCESS} in the handler, so it does not cause the shell-level non-zero exit.

Additional Context

The identical pattern exists in the SessionStart hook chain in older releases and was historically noisy; it was fixed by adding || true-style guards (see #1794, #1447). Applying the same fix to the UserPromptSubmit command closes the last remaining path that surfaces "No stderr output" to end users.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions