Bug
The SessionEnd hook (scripts/session-lifecycle-hook.mjs) hangs and gets cancelled by Claude Code when the broker process is unresponsive.
Error message:
SessionEnd hook [node "${CLAUDE_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs" SessionEnd] failed: Hook cancelled
Root Cause
sendBrokerShutdown() in scripts/lib/broker-lifecycle.mjs:43-57 creates a socket connection and waits for a data event after sending the shutdown message, but has no timeout:
export async function sendBrokerShutdown(endpoint) {
await new Promise((resolve) => {
const socket = connectToEndpoint(endpoint);
socket.setEncoding("utf8");
socket.on("connect", () => {
socket.write(`${JSON.stringify({ id: 1, method: "broker/shutdown", params: {} })}\n`);
});
socket.on("data", () => {
socket.end();
resolve();
});
socket.on("error", resolve);
socket.on("close", resolve);
});
}
If the broker process:
- Has the socket file present but is hung/zombie →
connect succeeds, data never fires
- Is slow to respond → Promise waits indefinitely
Claude Code's hook timeout eventually fires and kills the hook with "Hook cancelled".
Note: waitForBrokerEndpoint() at line 24 correctly has a timeoutMs = 2000 parameter. The shutdown call does not.
Suggested Fix
Add a timeout to the shutdown Promise:
export async function sendBrokerShutdown(endpoint) {
await new Promise((resolve) => {
const socket = connectToEndpoint(endpoint);
const timeout = setTimeout(() => {
socket.destroy();
resolve();
}, 3000); // 3s timeout — broker should respond quickly to shutdown
socket.setEncoding("utf8");
socket.on("connect", () => {
socket.write(`${JSON.stringify({ id: 1, method: "broker/shutdown", params: {} })}\n`);
});
socket.on("data", () => {
clearTimeout(timeout);
socket.end();
resolve();
});
socket.on("error", () => { clearTimeout(timeout); resolve(); });
socket.on("close", () => { clearTimeout(timeout); resolve(); });
});
}
Environment
- Claude Code CLI (macOS arm64, Darwin 25.3.0)
- Plugin version: codex 1.0.1 (from
openai-codex marketplace)
- Reproduction: use Codex companion during a session, then exit. If broker becomes unresponsive between session and shutdown, the SessionEnd hook hangs.
Impact
Non-blocking (session ends normally), but produces a confusing error message on every affected session exit. Users may think their session data was lost.
Bug
The
SessionEndhook (scripts/session-lifecycle-hook.mjs) hangs and gets cancelled by Claude Code when the broker process is unresponsive.Error message:
Root Cause
sendBrokerShutdown()inscripts/lib/broker-lifecycle.mjs:43-57creates a socket connection and waits for adataevent after sending the shutdown message, but has no timeout:If the broker process:
connectsucceeds,datanever firesClaude Code's hook timeout eventually fires and kills the hook with "Hook cancelled".
Note:
waitForBrokerEndpoint()at line 24 correctly has atimeoutMs = 2000parameter. The shutdown call does not.Suggested Fix
Add a timeout to the shutdown Promise:
Environment
openai-codexmarketplace)Impact
Non-blocking (session ends normally), but produces a confusing error message on every affected session exit. Users may think their session data was lost.