Hook callback ZodError (invalid_union, undefined control_response) in stdin reader is fatal to headless sessions
Summary
The CLI's control-protocol stdin reader throws an unhandled ZodError when a hook callback round-trip delivers undefined where the control_response union expects an object. The throw is fatal to the message-read loop: the subprocess dies before its first turn (headless runs record cost_usd: 0, session_id: null, and in some paths the misleading message Claude Code process aborted by user on fully headless runs where no user existed).
Error in hook callback hook_0
ZodError: [{ "code": "invalid_union", "errors": [[{"expected":"object","code":"invalid_type","path":[],"message":"Invalid input: expected object, received undefined"}], ...] }]
at processLine (/$bunfs/root/src/entrypoints/cli.js:44718:1786)
at read (/$bunfs/root/src/entrypoints/cli.js:44716:231)
Repro context
- Headless (
-p/ stream-json) sessions spawned as subprocesses by an orchestration harness, with hooks registered (PostToolUse / SessionStart; also observed independently with sub-agent Stop hooks receivingundefinedinput). - Intermittent — the same workload dies or survives depending on whether the malformed round-trip lands during a critical read. One team observed 5 subprocess deaths in one evening across independent runs; the same fingerprint recurred across multiple weeks.
Expected
The adjacent code path already logs dropped control_response with malformed response payload for non-object payloads — the union-parse path at processLine should degrade the same way (drop + log) instead of throwing and severing the control stream. A hook-input/control_response payload of undefined should never be process-fatal.
Notes
Consumer-side we have guarded our own hook callbacks against undefined input and added a one-shot retry for zero-cost spawn deaths (Unity-Technologies/wtf-harness#1242), but the throw itself is inside the CLI's bundled reader and can't be fixed from outside.