slopus/happy · warning
error
Error message
error
What it means
When handling the session-start hook throws (stdin parse error, handler exception), the server logs the error and responds 500 with body 'error' if headers haven't been sent. The logged 'error' corresponds to the caught exception surfaced in the handler's catch block.
Source
Thrown at packages/happy-cli/src/claude/utils/startHookServer.ts:140
} catch (parseError) {
logger.debug('[hookServer] Failed to parse hook data as JSON:', parseError);
}
// Support both snake_case (from Claude) and camelCase
const sessionId = data.session_id || data.sessionId;
if (sessionId) {
logger.debug(`[hookServer] Session hook received session ID: ${sessionId}`);
onSessionHook(sessionId, data);
} else {
logger.debug('[hookServer] Session hook received but no session_id found in data');
}
res.writeHead(200, { 'Content-Type': 'text/plain' }).end('ok');
} catch (error) {
clearTimeout(timeout);
logger.debug('[hookServer] Error handling session hook:', error);
if (!res.headersSent) {
res.writeHead(500).end('error');
}
}
return;
}
// 404 for anything else
res.writeHead(404).end('not found');
});
// Listen on random available port
server.listen(0, '127.0.0.1', () => {
const address = server.address();
if (!address || typeof address === 'string') {
reject(new Error('Failed to get server address'));
return;
}
const port = address.port;View on GitHub (pinned to b824cd0a46)
Solutions
- Inspect debug logs ('Error handling session hook:') for the underlying exception
- Validate that the hook client sends well-formed JSON and closes the stream cleanly
- Retry the hook invocation after fixing the payload
- Add explicit error normalization in the handler so failures produce actionable messages
Example fix
// before
const payload = JSON.parse(body.toString());
// after
let payload;
try { payload = JSON.parse(body.toString()); } catch { payload = {}; } Defensive patterns
Strategy: try-catch
Validate before calling
const body = JSON.stringify(sessionData); // throws early if not serializable
if (typeof sessionData !== 'object') throw new TypeError('session hook payload must be an object'); Try / catch
try {
const res = await fetch(hookUrl, { method: 'POST', body: JSON.stringify(sessionData) });
if (res.status === 500) {
logger.error('Hook handler failed; check happy-cli debug logs for Error handling session hook');
}
} catch (e) { /* network error */ } Prevention
- Send strictly JSON-serializable, well-formed payloads to the hook endpoint
- Check CLI debug output for the wrapped underlying exception
- Close the request stream cleanly to avoid partial-body parse errors
- Validate session data shape before posting
When it happens
Trigger: An exception inside the /hook/session-start handler — e.g. JSON.parse of malformed body, processing error, or stream read failure — triggers the catch path that writes the 500 'error' response.
Common situations: Hook client sends non-JSON or truncated payload; handler code throws on unexpected session data; request aborted mid-body causing read errors.
Related errors
AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31).
Data as JSON: /api/errors/b7d08f5d953e7864.
Report an issue: GitHub.