fix(proxy): stop empty 503 bodies becoming Codex Unknown error (#452)#463
Conversation
Wrap empty/non-JSON ChatGPT passthrough failures and drain responses as JSON so Codex always gets error.message. Also add openai-chat provider debug diagnostics for lidge-jun#452.
📝 WalkthroughWalkthroughThe PR standardizes empty-body upstream failures and server-draining responses as JSON 503/429-compatible envelopes, preserves validated retry headers, and adds redacted OpenAI chat request and stream diagnostics with unit and integration coverage. ChangesError handling and diagnostics
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant ResponsesCore
participant Upstream
participant ErrorFormatter
Client->>ResponsesCore: Send passthrough request
ResponsesCore->>Upstream: Fetch upstream response
Upstream-->>ResponsesCore: Return non-2xx status and body
ResponsesCore->>ErrorFormatter: Format status, body, and retry headers
ErrorFormatter-->>Client: Return structured JSON error
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Preserve non-empty upstream 400/5xx bytes and headers so Codex pool-retry activation and Claude Retry-After fidelity stay intact. Empty bodies still become JSON for lidge-jun#452.
Normalized empty-body passthrough errors keep a validated Retry-After with application/json. openai-chat diagnostics log only the host so Cloudflare account paths never appear.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/server/responses/passthrough-error.ts`:
- Around line 4-8: Extract the duplicated Retry-After validation into a shared
helper, using the existing implementation in core.ts as the single source of
truth. Remove the local sanitizedRetryAfter function from passthrough-error.ts
and import the shared helper, preserving the 128-character limit and
parseRetryAfterMs behavior for both passthrough and combo failures.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 61cb37ac-110c-472f-ad95-488b93de0053
📒 Files selected for processing (5)
src/adapters/openai-chat.tssrc/server/index.tssrc/server/responses/core.tssrc/server/responses/passthrough-error.tstests/issue-452-empty-503.test.ts
| function sanitizedRetryAfter(value: string | null | undefined, now: number): string | undefined { | ||
| const trimmed = value?.trim(); | ||
| if (!trimmed || trimmed.length > 128) return undefined; | ||
| return parseRetryAfterMs(trimmed, now) !== undefined ? trimmed : undefined; | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n "sanitizedRetryAfter" -g '*.ts' -B2 -A6Repository: lidge-jun/opencodex
Length of output: 157
🏁 Script executed:
#!/bin/bash
set -euo pipefail
git ls-files 'src/server/responses/passthrough-error.ts' 'src/**/core.ts' 'src/**/failover.ts' | sed 's#^`#FILE` #'
echo '---'
rg -n "sanitizedRetryAfter|parseRetryAfterMs|formatPassthroughUpstreamError|passthrough-error" src -g '*.ts' -A4 -B4Repository: lidge-jun/opencodex
Length of output: 12117
Extract sanitizedRetryAfter into a shared helper. src/server/responses/core.ts:291-294 and src/server/responses/passthrough-error.ts:4-7 duplicate the same Retry-After validation. Keep one source of truth so the 128-char guard and parse behavior can’t drift between passthrough and combo failures. Import it from a shared module instead of maintaining two copies.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/server/responses/passthrough-error.ts` around lines 4 - 8, Extract the
duplicated Retry-After validation into a shared helper, using the existing
implementation in core.ts as the single source of truth. Remove the local
sanitizedRetryAfter function from passthrough-error.ts and import the shared
helper, preserving the 128-character limit and parseRetryAfterMs behavior for
both passthrough and combo failures.
Summary
error.messageinstead ofUnknown error.503responses JSON (server_is_overloaded) withRetry-After: 5.debugProviderDiagnostichooks toopenai-chatsoocx debug provider logscaptures Xiaomi/openai-chat traffic.Test plan
bun run typecheckbun test ./tests/issue-452-empty-503.test.ts ./tests/shutdown-drain.test.ts ./tests/debug.test.tsocx debug provider on+logs -fshows openai-chat request linesSummary by CodeRabbit