Feature: PostToolUseFailure hook (failure-branch sibling of PostToolUse)
Problem
The PostToolUse hook fires only after a tool produces a successful output — run_post_tool_use_hooks is gated on success in core/src/tools/registry.rs. There is currently no hook surface for the failure branch: when a tool invocation errors, exits non-zero, times out, or returns an unsuccessful result. Hook authors who want to react to tool failures (diagnostics, automated retry guidance, failure telemetry, post-mortem capture) have no event to attach to.
Proposed design
Add a PostToolUseFailure hook event — the failure-branch sibling of PostToolUse:
- Matcher-bearing (matches on tool name) and turn-scoped — identical dispatch semantics to
PostToolUse. - Input mirrors the
PostToolUsecontract plus anerror_messagefield describing why the invocation failed. - Two failure sources are covered:
- handler error — tool identity recomputed from the pre-tool-use payload,
tool_response: null; - unsuccessful result — identity and the partial response taken from the post-tool-use payload.
- Fail-open: a failing hook subprocess never changes the underlying tool outcome.
This follows the established hook-event pattern (e.g. the recent SubagentStart / SubagentStop additions), so it is additive and low-risk to the rest of the hook system.
Why this is generic
Reacting to tool failures is a need independent of any particular integration — observability, retry/recovery UX, and failure analytics all want a hook here, and PostToolUse deliberately excludes the failure case. It rounds out the tool-lifecycle hook surface (PreToolUse → PostToolUse → PostToolUseFailure).
Offer
Per the contributing guidelines, I'm raising this as an issue first rather than an unsolicited PR. I have a complete, tested reference implementation against current main (enum variant, schema input/output wires + generated fixtures, dispatcher/runtime/registry wiring, unit tests; cargo fmt and clippy clean) and would be glad to submit a PR if the team feels this aligns with the roadmap and would like to invite one. Happy to iterate on the design (e.g. trimming the output contract to informational-only) based on your preferences.
2 Comments
Architecture analysis
I traced the existing hook dispatch path to validate the proposed design. The approach is architecturally sound and fits the existing system cleanly.
Current flow (the gap)
In
codex-rs/core/src/tools/registry.rs, the dispatch function:Two distinct failure cases both reach
None:handle_any_tool()returnsErr(FunctionCallError)— no tool output existssuccess_for_logging()isfalse(e.g. non-zero exit code) — tool output exists but is marked unsuccessfulFiles that need changes for
PostToolUseFailurecodex-rs/protocol/src/protocol.rs(~line 1352) — addPostToolUseFailuretoHookEventNameenumcodex-rs/hooks/src/schema.rs(~line 99) — add toHookEventNameWire; addPostToolUseFailureCommandInputstruct (mirrorsPostToolUseCommandInput+error: String+error_kind: String)codex-rs/hooks/src/engine/mod.rs(~line 64) — add"post-tool-use-failure"label inevent_name_label(), add dispatch methodscodex-rs/hooks/src/events/— newpost_tool_use_failure.rsfollowing the pattern ofpost_tool_use.rscodex-rs/hooks/src/registry.rs— register preview/run methodscodex-rs/core/src/hook_runtime.rs(~line 261) — addrun_post_tool_use_failure_hooks()alongsiderun_post_tool_use_hooks()codex-rs/core/src/tools/registry.rs(~line 582) — callrun_post_tool_use_failure_hooks()in the!successbranchcodex-rs/hooks/schema/generated/— regenerate schema fixturesInput contract suggestion
The
error_kindfield distinguishes the two failure cases so hook authors can filter precisely. Whenerror_kind = "handler_error", there is notool_response; whenerror_kind = "unsuccessful_result", the partial tool output is available.Output contract
Since the tool has already failed,
PostToolUseFailuredoes not need adecision: blocksemantic — it is purely observational.HookUniversalOutputWire(supportingstop/continue) is sufficient, consistent with the author's stated intent.The overall design follows the
SubagentStart/SubagentStopandPreCompact/PostCompactsymmetric-event precedent and is entirely additive.Happy to submit a PR if the team would like to invite one.
@JunJieLiu51520, please stop spamming our issue tracker with AI-generated posts. It's generating a lot of noise, and it's not helpful.