Repository navigation
fix(opencode): retry OpenRouter upstream errors reported inside a 200 stream - #47
Merged
Merged
Conversation
…stream OpenRouter forwards upstream 429s and 5xxs as a JSON object in the SSE body, so they arrive as UnknownError with no statusCode and the retry classifier never saw them. Apply the same rule the APIError branch uses. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
1 similar comment
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
|
The following comment was made by an LLM, it may be inaccurate: |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Author
|
/devin review |
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A sandbox turn that hits an upstream rate limit or a dropped stream on an OpenRouter-routed model now retries instead of dying on the first hit. Every customer build on those models today ends at the first provider hiccup; this makes them survive the ordinary ones.
Context
OpenRouter forwards upstream failures as a JSON object inside the HTTP 200 SSE body, e.g.
{"code":502,"message":"Upstream error from Together: Stream error: h2 protocol error…","metadata":{"error_type":"provider_unavailable"}}. The OpenRouter SDK emits that as a stream error rather than anAPICallError, so opencode wraps it asUnknownErrorwith the JSON as its message and nostatusCode.retryable()then never reaches the status branch that retries any 5xx, and its JSON branch only readscodewhen it is a string, so OpenRouter's numericcodematches nothing. Result: no retry, turn fails.Observed across the cheap-model bakeoff in andytown: every DeepSeek V4.1 Flash unit died on a 429 last week and seven Together stream drops killed three of four units today (
bakeoff-r5-grok-ds41), none retried. Same-model retry is the only recovery path in production; the model-fallback config the coordinator ships is not executed by anything (REPL-31522). Upstream has the identical gap and closed it as not planned: anomalyco#22448.Change
In the JSON branch of
retryable(), apply the rule theAPIErrorbranch already uses: a numericcodeof 429 retries as rate-limited, a numericcodeof 500 or above retries as a transient provider failure. Nothing else changes: same backoff, same attempt cap, and 4xx request errors (for example a rejected tool schema) still do not retry.Testing Done
Three new cases in
test/session/retry.test.tsusing the real payloads from the failed sessions: the 429rate_limit_exceeded, the Together 502provider_unavailable, and a 400 schema rejection that must not retry.bun test test/session/retry.test.ts: 36 pass, 0 fail.Follow-up once tagged: bump
OPENCODE_VERSIONin andytown's snapshot Dockerfile and rerun the DeepSeek rows.🤖 Generated with Claude Code
Summary by cubic
Retries OpenRouter upstream errors that arrive as JSON inside a 200 SSE stream, so sandbox turns survive rate limits and provider 5xxs instead of dying on the first hiccup. Previously these errors were treated as unknown with no numeric status, so they never triggered a retry. 4xx request errors (like a rejected tool schema) still don't retry.
APIErrorbranch: numeric 429 retries as rate-limited, numeric 5xx retries as a transient provider failure.Written for commit c357efb. Summary will update on new commits.