Hook failure messages should identify the failing hook and expose diagnostics
What problem are you seeing?
When a hook fails, Codex currently surfaces a very terse message such as:
SessionStart hook (failed)
error: hook returned invalid session start JSON output
or:
PostToolUse hook (failed)
error: hook exited with code 1
This tells the user that a hook failed, but not enough to debug it when multiple hooks are configured. In practice, the user still has to manually inspect config files and scripts to answer basic questions:
- Which configured hook failed?
- Where was it configured?
- What command/script was executed?
- What was the exit code?
- Did stdout contain invalid JSON, mixed logs, or no output?
- Did stderr contain a useful error message?
I hit this on Codex CLI 0.136.0 with both SessionStart and PostToolUse failures in a hooks-heavy setup. The task itself could continue, but the hook failure surface was too opaque to quickly diagnose.
Requested improvement
Please make hook failure diagnostics identify the failing hook and expose a small, safe diagnostic block.
Useful fields would be:
hook_event: PostToolUse
hook_name_or_id: <configured name/id if available>
config_source: <path or profile source, secrets redacted>
command: <script/command path, secrets redacted>
exit_code: 1
stderr_tail: <last N lines>
stdout_tail: <last N lines, if safe>
stdout_parse_error: expected JSON object, got non-JSON output / empty output / mixed log output
For JSON-producing hooks, it would be especially helpful to distinguish:
- stdout was empty
- stdout was invalid JSON
- stdout contained valid JSON plus extra non-JSON logs
- stdout had unsupported fields
- hook exited non-zero before producing output
UI / workflow ideas
A failure message could show a compact summary with expandable details:
PostToolUse hook "my-hook-name" failed
source: ~/.codex/hooks.json
command: /path/to/script
exit_code: 1
stderr_tail: ...
stdout_parse_error: expected JSON object, received non-JSON log output
Actions that would reduce debugging friction:
- Copy diagnostics
- Open hook config
- Temporarily disable this hook for this session
- Show docs link for expected JSON schema for that hook event
Why this matters
Hooks are an advanced-user feature, but the current failure display is opaque even for advanced users. The result is that a 30-second script/config bug becomes a 10-minute hunt through hook sources.
This is also important for trust: if hooks can affect session startup or tool lifecycle behavior, users should be able to see exactly which hook failed and why.
Related issues I found before filing
This is adjacent to, but broader than:
- #18887: Stop hook invalid JSON error is too opaque for unsupported fields
- #22847: unable to trust hooks, error in CLI
- #23645: Computer Use get_app_state hang and relative hook path failure are hard to diagnose
- #26675: Plugin PostToolUse hook relative command resolves from workspace cwd
Those cover specific hook problems. This issue is about the general diagnostic surface for hook failures across hook event types.
Environment
- Codex CLI:
0.136.0 - Platform: macOS
- Account/profile used to file:
Fearvox
4 Comments
I implemented a candidate fix on a fork branch, but this repository currently only allows collaborators to open pull requests.
Branch:
https://github.com/Fearvox/codex/tree/hook-failure-diagnostics
Compare:
https://github.com/openai/codex/compare/main...Fearvox:hook-failure-diagnostics
Summary:
Validation:
https://github.com/Fearvox/codex/pull/1
This is the PR in my forked repo, for better reviewing experience.
I hope this gets fixed. Just switched to Codex CLI and pretty irritating that every response starts with three or four "SessionStart hook (failed) / error: hook exited with code 1" messages. No info what hooks it's reporting on, what it implies, how to fix them. Are those warnings or errors.
Corroborating this on 0.149.1, with a correction after tracing the exact release parser.
Every user turn produced two identical failure cards:
Two separate hook registrations emitted syntactically valid JSON shaped like:
In 0.149.1,
UserPromptSubmitHookSpecificOutputWirerejects unknown fields and accepts onlyhookEventNameplus optionaladditionalContext.suppressOutputbelongs to the top-level universal output object, so an actionable diagnostic would have been:Moving
suppressOutputto the top level makes the payload schema-valid, although the field is currently parsed but not implemented.Instead, two different registrations collapsed to the same generic error, with neither the command nor configuration source identified. Multiple hook sources had been merged into the effective registration list, so auditing only the project hook configuration showed nothing wrong; one failing registration came from a second file outside it.
One important correction to an initially tempting diagnosis: on 0.149.1,
exit 0with empty stdout is a successful no-op,{}is valid, and plain text fromUserPromptSubmitis accepted as additional context. A silent hook was therefore not the culprit. The generic error sent the investigation toward the wrong hook and cost several hours before the real registration was found.The failing hook emitted the illegal member only when it had something to report, so it appeared healthy under a trivial test prompt.
The configuration source, command, and field-level stdout parse diagnostics proposed in this issue would have reduced this to a one-minute fix. This seems squarely within #27052; #18887 is the closely related unsupported-field case.
Minimal reproduction: configure a
UserPromptSubmithook to emit the JSON above. A command hook that exits 0 with empty stdout does not reproduce the failure.