Skip to content

vercel plugin: SessionEnd hook (session-end-cleanup.mjs) intermittently fails with "Hook cancelled" — missing timeout in hooks.json #5603

Description

@jg-shoealls

Title

vercel plugin: SessionEnd hook (session-end-cleanup.mjs) intermittently fails with "Hook cancelled" — missing timeout in hooks.json

Environment

  • Plugin: vercel@claude-plugins-official, version 0.45.1 (confirmed latest via claude plugin update)
  • OS: Windows 10, Git Bash shell
  • Node: v24.15.0
  • Trigger context observed: non-interactive claude -p "<prompt>" session

Summary

The vercel plugin's SessionEnd hook (hooks/session-end-cleanup.mjs) occasionally fails at session teardown with:

SessionEnd hook [node "${CLAUDE_PLUGIN_ROOT}/hooks/session-end-cleanup.mjs"] failed: Hook cancelled

Root cause (as far as I could determine)

Looking at hooks/hooks.json in the installed plugin:

"SessionEnd": [
  {
    "hooks": [
      {
        "type": "command",
        "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-end-cleanup.mjs\""
      }
    ]
  }
]

This is the only hook entry in the file with no "timeout" field — every other hook in the same plugin (and in other plugins, e.g. claude-mem) declares one.

session-end-cleanup.mjs reads its session id synchronously from stdin:

function parseSessionIdFromStdin() {
  return normalizeSessionEndSessionId(parseSessionEndHookInput(readFileSync(0, "utf8")));
}

Manually piping valid input into the script completes instantly and exits 0:

echo '{"session_id":"abc123"}' | node session-end-cleanup.mjs
# exit 0, immediate

So the script logic itself is not the problem. The suspicion is that when the harness doesn't close stdin promptly for this hook (observed specifically after a non-interactive claude -p session on Windows), the blocking readFileSync(0, ...) call hangs until some default/harness-level cancellation kicks in — which would explain "Hook cancelled" rather than a script error or non-zero exit.

Impact

Low / cosmetic. The hook only deletes temp files matching vercel-plugin-<sessionId>-* in the OS temp dir. A cancelled run just leaves those temp files behind; no data loss or effect on session behavior.

Suggested fix

  • Add an explicit "timeout" to the SessionEnd hook entry in hooks.json, consistent with the other hooks in the plugin.
  • Consider making the stdin read robust to a not-yet-closed stream (e.g., an explicit read timeout/fallback inside session-end-cleanup.mjs itself) rather than relying solely on the harness's hook-level timeout.

Repro steps

  1. Install vercel@claude-plugins-official (v0.45.1).
  2. Run a non-interactive session: claude -p "<any task-oriented prompt>" on Windows.
  3. Observe the SessionEnd hook [...] failed: Hook cancelled message at teardown (intermittent, not on every run).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions