Skip to content

fix: handle Codex turn.failed errors and add model selection#414

Merged
pedramamini merged 1 commit intomainfrom
fix/codex-turn-failed-and-model-selection
Feb 19, 2026
Merged

fix: handle Codex turn.failed errors and add model selection#414
pedramamini merged 1 commit intomainfrom
fix/codex-turn-failed-and-model-selection

Conversation

@pedramamini
Copy link
Collaborator

@pedramamini pedramamini commented Feb 18, 2026

Summary

  • Handle turn.failed events in the Codex output parser — previously these fell through to a generic system event, causing raw JSON to leak into the terminal instead of a clean error message
  • Add -m, --model support to Codex agent definition so users can override the model from Settings or per-session, instead of relying solely on ~/.codex/config.toml
  • Add missing model entries to MODEL_CONTEXT_WINDOWS (gpt-5.1-codex, gpt-5.2-codex, gpt-5.3 family)

Closes #392

Details

The reporter's Codex agent was exiting with code 1 and displaying raw JSON like:

{"type":"turn.failed","error":{"message":"stream disconnected before completion: The model gpt-5.3-codex does not exist..."}}

Root causes:

  1. CodexRawMessage.type didn't include turn.failed — the parser's transformMessage() fell to the default case, emitting it as a silent system event
  2. The error field type was string but Codex sends { message, type } objects for turn.failed
  3. detectErrorFromLine() didn't check for turn.failed (Claude's parser already handled this pattern)
  4. No modelArgs or model config option existed for Codex despite the CLI supporting -m, --model

Changes:

  • codex-output-parser.ts: Added turn.failed to type union, updated error field to string | { message?, type? }, added handlers in both transformMessage() and detectErrorFromLine()
  • definitions.ts: Added modelArgs and model config option (text field, empty default = use config.toml)
  • Updated test suite with turn.failed coverage

Test plan

  • Verify turn.failed events display as clean error messages in the terminal
  • Verify model override works via Settings → Codex → Model
  • Verify empty model field falls back to ~/.codex/config.toml default

Summary by CodeRabbit

  • New Features

    • Added a model selection option in the Codex agent configuration UI for easy model override.
    • Extended support for new GPT-5 Codex model variants (gpt-5.1, gpt-5.2, gpt-5.3, and specialized variants).
  • Bug Fixes

    • Improved error message extraction and handling for failed turn events with better nested error detection.
  • Tests

    • Expanded test coverage for error parsing and turn.failed event scenarios.

Codex CLI emits turn.failed events for API errors (model not found,
stream disconnections) but the parser didn't handle this type, causing
raw JSON to leak into the terminal. Also adds -m/--model support so
users can override the model from Maestro's UI instead of relying
solely on ~/.codex/config.toml.

Closes #392
@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

This PR extends the Codex agent with support for new GPT-5.x model variants (5.1, 5.2, 5.3), introduces a model override configuration option via command-line argument builder, and enhances error handling to parse turn.failed events and object-form error messages. Corresponding test coverage is added for error parsing scenarios.

Changes

Cohort / File(s) Summary
Test Coverage
src/__tests__/main/parsers/codex-output-parser.test.ts
Added 65 lines of tests covering error parsing: object error with message field, turn.failed events with nested/string errors, default error text, and agent identification from turn.failed JSON.
Agent Configuration
src/main/agents/definitions.ts
Added model argument builder at agent level and new UI config option for Codex to allow model override via -m flag. Context window description updated to mention GPT-5.2/5.3 variants and clarified default behavior for GPT-5.2+ models.
Parser Implementation
src/main/parsers/codex-output-parser.ts
Expanded model context window mapping to include gpt-5.1-codex, gpt-5.2-codex, gpt-5.3, gpt-5.3-codex, and gpt-5.3-codex-max variants. Extended CodexRawMessage type union to include turn.failed and expanded error field to support string or object form. Enhanced error extraction logic in message transformation and JSON line parsing to handle structured and unstructured error formats.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the two main changes: handling turn.failed errors and adding model selection support to Codex.
Linked Issues check ✅ Passed All code-related requirements from issue #392 are addressed: turn.failed errors are handled, model selection is added via config, and missing Codex models are registered.
Out of Scope Changes check ✅ Passed All changes are directly scoped to addressing issue #392: parser enhancements, error handling, model configuration, and supporting tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/codex-turn-failed-and-model-selection

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link

greptile-apps bot commented Feb 18, 2026

Greptile Summary

Fixed Codex agent error handling by adding turn.failed event support and model selection capability.

Key Changes:

  • Added turn.failed to message type union and updated error field to handle both string and object formats
  • Implemented error extraction in both transformMessage() and detectErrorFromLine() to properly parse nested error objects
  • Added modelArgs function and model config option to enable -m flag for model override (consistent with OpenCode pattern)
  • Added missing model entries to MODEL_CONTEXT_WINDOWS (gpt-5.1-codex, gpt-5.2-codex, gpt-5.3 family)
  • Comprehensive test coverage for all turn.failed error formats

Impact:

  • Users now see clean error messages instead of raw JSON when Codex encounters API errors or model access issues
  • Model can be overridden via Settings UI or per-session, falling back to ~/.codex/config.toml when empty
  • Follows established patterns from Claude Code parser and OpenCode configuration

Confidence Score: 5/5

  • Safe to merge - focused bug fix with comprehensive test coverage
  • The implementation follows established patterns from Claude parser, includes thorough test coverage for all error cases, and the model configuration matches the existing OpenCode pattern. Changes are surgical and address the reported issue directly without introducing side effects.
  • No files require special attention

Important Files Changed

Filename Overview
src/main/parsers/codex-output-parser.ts Added turn.failed event handling with proper error extraction from nested objects, updated type definitions, and added missing GPT-5.x model entries to context window map
src/main/agents/definitions.ts Added modelArgs function and model config option with argBuilder to enable model override via CLI -m flag and Settings UI
src/tests/main/parsers/codex-output-parser.test.ts Added comprehensive test coverage for turn.failed events including nested error objects, string errors, and empty error cases

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Start[Codex CLI Output] --> Parse[parseJsonLine]
    Parse --> Transform[transformMessage]
    
    Transform --> CheckType{Check message type}
    
    CheckType -->|turn.failed| ExtractError[Extract error field]
    ExtractError --> CheckErrorType{error type?}
    CheckErrorType -->|object with message| UseMessage[Use error.message]
    CheckErrorType -->|string| UseString[Use error string]
    CheckErrorType -->|empty/null| UseDefault[Use 'Turn failed']
    
    UseMessage --> ReturnError[Return error event]
    UseString --> ReturnError
    UseDefault --> ReturnError
    
    CheckType -->|error| HandleError[Handle error type]
    HandleError --> CheckErrorType
    
    CheckType -->|other types| ProcessNormal[Process normally]
    
    ReturnError --> Display[Display clean error in terminal]
    ProcessNormal --> Display
    
    subgraph "Model Selection"
        Settings[Settings UI] -->|model field| ArgBuilder[argBuilder function]
        ArgBuilder -->|if not empty| AddModelArg[Add -m modelId args]
        ArgBuilder -->|if empty| UseDefault2[Use config.toml default]
    end
    
    AddModelArg --> SpawnCodex[Spawn Codex CLI]
    UseDefault2 --> SpawnCodex
Loading

Last reviewed commit: 580fd8b

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/main/parsers/codex-output-parser.ts (1)

490-498: Consider consolidating turn.failed error extraction for consistency.

The condition on line 494 only matches turn.failed with object errors (parsed.error?.message), while string errors fall through to the generic else if (parsed.error) on line 497. This works correctly but the comment on line 495 could mislead readers into thinking turn.failed only supports object errors.

For clarity, consider handling turn.failed the same way as the transformMessage method does:

♻️ Optional: Consolidate turn.failed handling
 			if (parsed.type === 'error' && parsed.error) {
 				errorText =
 					typeof parsed.error === 'string' ? parsed.error : parsed.error?.message || JSON.stringify(parsed.error);
-			} else if (parsed.type === 'turn.failed' && parsed.error?.message) {
-				// Handle turn.failed format: {"type":"turn.failed","error":{"message":"..."}}
-				errorText = parsed.error.message;
+			} else if (parsed.type === 'turn.failed') {
+				// Handle turn.failed format: error can be string or { message: "..." }
+				errorText =
+					typeof parsed.error === 'object' && parsed.error?.message
+						? parsed.error.message
+						: typeof parsed.error === 'string'
+							? parsed.error
+							: 'Turn failed';
 			} else if (parsed.error) {
 				errorText = typeof parsed.error === 'string' ? parsed.error : parsed.error?.message || JSON.stringify(parsed.error);
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/parsers/codex-output-parser.ts` around lines 490 - 498, Consolidate
the 'turn.failed' branch so it extracts error text the same way as the generic
error handling: when parsed.type === 'turn.failed' treat parsed.error uniformly
(support string or object with message) instead of only checking
parsed.error?.message; update the conditional around parsed.type ===
'turn.failed' in codex-output-parser (where parsed.type is inspected) to mirror
the extraction logic used for parsed.type === 'error' (use typeof parsed.error
=== 'string' ? parsed.error : parsed.error?.message ||
JSON.stringify(parsed.error)).
src/__tests__/main/parsers/codex-output-parser.test.ts (1)

487-498: Consider asserting the specific error type for completeness.

The test validates that an error is detected from turn.failed JSON and that agentId is 'codex', but doesn't assert the specific error.type value. Adding this assertion would strengthen the test.

🧪 Optional: Add error type assertion
 		it('should detect errors from turn.failed JSON', () => {
 			const line = JSON.stringify({
 				type: 'turn.failed',
 				error: {
 					message:
 						'stream disconnected before completion: The model gpt-5.3-codex does not exist or you do not have access to it.',
 				},
 			});
 			const error = parser.detectErrorFromLine(line);
 			expect(error).not.toBeNull();
 			expect(error?.agentId).toBe('codex');
+			// The error message should match one of the known patterns or fall through as generic
+			expect(error?.type).toBeDefined();
 		});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/__tests__/main/parsers/codex-output-parser.test.ts` around lines 487 -
498, The test should also assert the parsed error's specific type: after calling
parser.detectErrorFromLine(line) and the existing agentId assertion, add an
expectation on error?.type (e.g.,
expect(error?.type).toBe('<expected_error_type>')) so the test verifies the
parser returns the correct semantic error type for the 'turn.failed' JSON;
update the assertion next to the existing expect(error?.agentId).toBe('codex')
and use the concrete error type your parser maps that message to.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/__tests__/main/parsers/codex-output-parser.test.ts`:
- Around line 487-498: The test should also assert the parsed error's specific
type: after calling parser.detectErrorFromLine(line) and the existing agentId
assertion, add an expectation on error?.type (e.g.,
expect(error?.type).toBe('<expected_error_type>')) so the test verifies the
parser returns the correct semantic error type for the 'turn.failed' JSON;
update the assertion next to the existing expect(error?.agentId).toBe('codex')
and use the concrete error type your parser maps that message to.

In `@src/main/parsers/codex-output-parser.ts`:
- Around line 490-498: Consolidate the 'turn.failed' branch so it extracts error
text the same way as the generic error handling: when parsed.type ===
'turn.failed' treat parsed.error uniformly (support string or object with
message) instead of only checking parsed.error?.message; update the conditional
around parsed.type === 'turn.failed' in codex-output-parser (where parsed.type
is inspected) to mirror the extraction logic used for parsed.type === 'error'
(use typeof parsed.error === 'string' ? parsed.error : parsed.error?.message ||
JSON.stringify(parsed.error)).

@pedramamini pedramamini merged commit 04a2074 into main Feb 19, 2026
2 checks passed
@pedramamini pedramamini deleted the fix/codex-turn-failed-and-model-selection branch February 19, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] gpt-5.3-codex does not exist

1 participant

Comments