From e44c6d9d7d26447213422939fa93a84dd5054c7b Mon Sep 17 00:00:00 2001 From: Leandro Barbosa Date: Fri, 13 Feb 2026 14:31:22 -0300 Subject: [PATCH] fix: handle codex CLI stderr noise without losing valid stdout Codex writes diagnostic messages to stderr (e.g. rollout errors) which cause non-zero exit codes even when valid JSONL output exists on stdout. Parse stdout first before checking exit code to avoid false errors. --- pkg/providers/codex_cli_provider.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/pkg/providers/codex_cli_provider.go b/pkg/providers/codex_cli_provider.go index 37cfd9314..8886406b4 100644 --- a/pkg/providers/codex_cli_provider.go +++ b/pkg/providers/codex_cli_provider.go @@ -50,10 +50,22 @@ func (p *CodexCliProvider) Chat(ctx context.Context, messages []Message, tools [ cmd := exec.CommandContext(ctx, p.command, args...) cmd.Stdin = bytes.NewReader([]byte(prompt)) - var stderr bytes.Buffer + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout cmd.Stderr = &stderr - stdout, err := cmd.Output() + err := cmd.Run() + + // Parse JSONL from stdout even if exit code is non-zero, + // because codex writes diagnostic noise to stderr (e.g. rollout errors) + // but still produces valid JSONL output. + if stdoutStr := stdout.String(); stdoutStr != "" { + resp, parseErr := p.parseJSONLEvents(stdoutStr) + if parseErr == nil && resp != nil && (resp.Content != "" || len(resp.ToolCalls) > 0) { + return resp, nil + } + } + if err != nil { if ctx.Err() == context.Canceled { return nil, ctx.Err() @@ -64,7 +76,7 @@ func (p *CodexCliProvider) Chat(ctx context.Context, messages []Message, tools [ return nil, fmt.Errorf("codex cli error: %w", err) } - return p.parseJSONLEvents(string(stdout)) + return p.parseJSONLEvents(stdout.String()) } // GetDefaultModel returns the default model identifier.