Error Handling Strategy for Codex Reviews in the OpenAI Plugin
The Codex plugin converts every failure—from network timeouts to schema violations—into actionable user guidance rather than exposing raw stack traces or cryptic exceptions.
The openai/codex-plugin-cc repository implements a defensive, multi-layered error handling strategy for Codex reviews that validates data at the protocol, schema, and application layers. Every request to the Codex App Server is wrapped in validation logic that ensures users receive clear recovery instructions instead of unhandled exceptions.
Protocol-Level Type Safety
The error handling strategy begins with compile-time guarantees defined in plugins/codex/scripts/lib/app-server-protocol.d.ts. At line 66, the protocol file defines the "review/start" request as an operation that must return a ReviewStartResponse object. This TypeScript contract ensures the client expects a specific shape before any network call executes, preventing type mismatches at the boundary between the plugin and the App Server.
Request Validation in the Companion Script
When a review is initiated, codex-companion.mjs executes the request inside a defensive try / catch block around line 1020. The code explicitly validates the response structure before proceeding:
// From codex-companion.mjs (~line 1020)
try {
const response = await client.request("review/start", params);
if (!response.reviewThreadId) {
throw new Error("Review start succeeded but no thread ID returned");
}
// ...process successful response...
} catch (e) {
throw new Error(`Failed to start Codex review: ${e.message}`);
}
If the response lacks required fields like reviewThreadId, the script throws immediately with a descriptive message. Any network or protocol error caught in the outer block is re-thrown with context, ensuring the user sees what failed rather than a raw exception.
JSON Schema Validation
After receiving raw JSON from the App Server, the companion script validates the payload against plugins/codex/schemas/review-output.schema.json. If schemaValidate returns invalid, the code throws a specific error advising manual intervention:
// Schema validation in codex-companion.mjs
const parseResult = schemaValidate(output, REVIEW_SCHEMA);
if (!parseResult.valid) {
throw new Error(
`Codex returned JSON with an unexpected review shape. ` +
`Run /codex:review --wait manually or bypass the gate.`
);
}
This step catches malformed data that passes TypeScript compilation but violates runtime constraints, such as missing review fields or incorrect data types.
Stop-Review Gate Failure Handling
The stop-review-gate-hook.mjs implements the final safety layer, intercepting failures after each Claude turn. It explicitly guards against three distinct error modes:
- No final output (lines 70–78): Returns "The stop-time Codex review task returned no final output. Run
/codex:review --waitmanually or bypass the gate." - Invalid JSON (lines 86–94): Returns "The stop-time Codex review task returned invalid JSON. Run
/codex:review --waitmanually or bypass the gate." - Timeout (lines 112–118): Returns "The stop-time Codex review task timed out after 15 minutes. Run
/codex:review --waitmanually or bypass the gate."
// From stop-review-gate-hook.mjs
if (!review.ok) {
const msg = review.reason
? `The stop-time review failed: ${review.reason}`
: "The stop-time review task returned no final output. Run `/codex:review --wait` manually.";
return { ok: false, reason: msg };
}
In each case, the hook prevents error propagation and surfaces a clear instruction for recovery.
Summary
- Type-safe protocol definitions in
app-server-protocol.d.tsenforce contract boundaries at compile time. - Runtime validation in
codex-companion.mjschecks for required fields likereviewThreadIdand wraps network calls in descriptive error handlers. - JSON schema validation ensures the review output structure matches expected shapes before processing continues.
- Stop-review gate monitoring catches timeouts, parse errors, and empty responses with specific user actions.
- Actionable feedback replaces all stack traces; every error message includes instructions to run
/codex:review --waitor disable the gate.
Frequently Asked Questions
What happens if the Codex App Server returns malformed JSON?
The companion script validates the payload against review-output.schema.json using schemaValidate(). If validation fails, it throws an error stating the JSON has an unexpected shape and advises the user to run /codex:review --wait manually or bypass the gate.
How does the plugin handle network timeouts during reviews?
The stop-review-gate-hook.mjs monitors review tasks for a 15-minute timeout threshold. If exceeded, it returns a user-friendly message stating the task timed out and suggests running /codex:review --wait manually or disabling the gate, rather than surfacing a raw timeout exception.
What error appears if the review thread ID is missing?
In codex-companion.mjs, the code explicitly checks if (!response.reviewThreadId) immediately after the App Server response. If missing, it throws "Review start succeeded but no thread ID returned", preventing the workflow from continuing with undefined state.
Can users bypass the review gate if errors persist?
Yes. Every error message generated by the stop-review gate includes explicit instructions to either run /codex:review --wait manually to retry the review, or to bypass the gate entirely, ensuring users can recover from persistent failures without restarting the application.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →