# Error Handling Strategy for Codex Reviews in the OpenAI Plugin

> Discover the error handling strategy for Codex reviews in the OpenAI plugin. Learn how failures are converted into actionable user guidance not raw exceptions.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: architecture
- Published: 2026-07-07

---

**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`](https://github.com/openai/codex-plugin-cc/blob/main/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:

```typescript
// 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`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/schemas/review-output.schema.json). If `schemaValidate` returns invalid, the code throws a specific error advising manual intervention:

```typescript
// 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 --wait` manually or bypass the gate."*
- **Invalid JSON** (lines 86–94): Returns *"The stop-time Codex review task returned invalid JSON. Run `/codex:review --wait` manually or bypass the gate."*
- **Timeout** (lines 112–118): Returns *"The stop-time Codex review task timed out after 15 minutes. Run `/codex:review --wait` manually or bypass the gate."*

```javascript
// 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.ts`](https://github.com/openai/codex-plugin-cc/blob/main/app-server-protocol.d.ts) enforce contract boundaries at compile time.
- **Runtime validation** in `codex-companion.mjs` checks for required fields like `reviewThreadId` and 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 --wait` or 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`](https://github.com/openai/codex-plugin-cc/blob/main/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.