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

  1. Inspect debug logs ('Error handling session hook:') for the underlying exception
  2. Validate that the hook client sends well-formed JSON and closes the stream cleanly
  3. Retry the hook invocation after fixing the payload
  4. 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

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.