Skip to content

fix(sse): stop stream readiness from treating a choices-less error frame as success (#7503) - #8504

Merged
diegosouzapw merged 1 commit into
release/v3.8.49from
fix/7503-empty-choices-stream-readiness
Jul 25, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.49from
fix/7503-empty-choices-stream-readiness

Conversation

@diegosouzapw

@diegosouzapw diegosouzapw commented Jul 25, 2026 •

Copy link
Copy Markdown
Collaborator

Refs #7503

Root cause

When a mid-stream provider failure (e.g. the auggie CLI passthrough executor failing to spawn its local binary) emits an SSE data: {"error":{...}} frame with no choices key, OmniRoute's stream-readiness gate (open-sse/utils/streamReadiness.ts) classified that frame as a valid "ready" (successful) stream signal, because hasNonPingStructuredPayload() treated ANY non-empty JSON object — including a bare {error:...} frame — as readiness confirmation. This blocked combo fallback to the next candidate and let the malformed frame reach the client as a fake HTTP 200. OpenAI-SDK-based clients (VS Code Copilot, Cline) then throw a hard client-side error because they never received a single populated choices entry for the whole request — "Response contained no choices."

Fix

hasNonPingStructuredPayload() now recognizes an error-only structured payload (has an error key, and none of the content-bearing keys — choices, candidates, delta, tool_calls, etc.) and does NOT treat it as a readiness signal. A stream that only ever emits such frames now falls through to the existing STREAM_EARLY_EOF / timeout failure paths, which combo already uses to fail over to the next candidate. Frames that legitimately carry both an error field and real content-bearing keys are unaffected.

Regression test (Hard Rule #18)

tests/unit/repro-7503-no-choices.test.ts — RED before the fix, GREEN after.

RED:
✖ hasStreamReadinessSignal wrongly reports readiness for a choices-less mid-stream error frame (9.3ms)
  AssertionError [ERR_ASSERTION]: ... true !== false
✔ AuggieExecutor's real streaming error path emits an SSE body with zero populated `choices` (end-to-end) (156.3ms)
ℹ tests 2, pass 1, fail 1

GREEN:
✔ hasStreamReadinessSignal wrongly reports readiness for a choices-less mid-stream error frame (15.9ms)
✔ AuggieExecutor's real streaming error path emits an SSE body with zero populated `choices` (end-to-end) (176.9ms)
ℹ tests 2, pass 2, fail 0

Gates run

  • npm run typecheck:core — clean
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json open-sse/utils/streamReadiness.ts tests/unit/repro-7503-no-choices.test.ts — clean
  • node scripts/check/check-file-size.mjs — same 5 pre-existing frozen violations as the pure release/v3.8.49 tip (tokenHealthCheck.ts, sse/handlers/chat.ts, sse/services/auth.ts, accountFallback.ts, combo.ts); nothing new
  • node scripts/check/check-complexity.mjs — reports 2169 > baseline 2130, but probed against a throwaway detached worktree of the pure origin/release/v3.8.49 tip: identical violation set (only line numbers shift), so this is pre-existing drift, not introduced here
  • node scripts/check/check-cognitive-complexity.mjs — same: 956 > baseline 951 reproduces identically on the pure tip in a throwaway probe worktree; not introduced by this PR
  • node scripts/check/check-changelog-integrity.mjs — OK
  • node scripts/check/check-test-discovery.mjs — OK, new test file discovered
  • node --import tsx/esm --test tests/unit/stream-readiness.test.ts tests/unit/combo-stream-readiness-fallback.test.ts tests/unit/stream-readiness-policy.test.ts tests/unit/runtime-timeouts.test.ts tests/unit/executor-kiro.test.ts tests/unit/auggie-executor.test.ts — 90/90 pass, no regressions in the existing stream-readiness/combo-fallback/executor suites

⚠️ Scope note (maintainer audit): switched Closes → Refs. This PR fixes the proven hasStreamReadinessSignal() defect (a choices-less {error:…} SSE frame classified as a READY stream), which is the reported symptom's mechanism. It does not yet reconcile the AUTO_COMBO_NOAUTH_ALLOWLIST gate in open-sse/services/autoCombo/virtualFactory.ts, which the analysis flagged as a secondary lead to carry into the fix (the flat variant auto/best-coding-fast reaching auggie). #7503 stays open until that angle is closed out.

@diegosouzapw
diegosouzapw merged commit 9ced2e9 into release/v3.8.49 Jul 25, 2026
10 checks passed
@diegosouzapw
diegosouzapw deleted the fix/7503-empty-choices-stream-readiness branch July 25, 2026 11:14
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
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.

2 participants