fix(opencode): classify OpenRouter's typeless 5xx chunks as retryable APIError - #44
Open
PierrotAWB wants to merge 1 commit into
Open
PierrotAWB wants to merge 1 commit into
PierrotAWB wants to merge 1 commit into
Conversation
… APIError
OpenRouter relays upstream failures (provider unavailable, upstream connect
errors, idle timeouts) mid-stream as { code: 5xx, message } with no type
field, so parseStreamError returned undefined and the turn died as a
non-retryable UnknownError. Treat any typeless numeric 5xx code as a
retryable provider error so the session's retry loop handles it.
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. |
|
The following comment was made by an LLM, it may be inaccurate: |
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/opencode/src/provider/error.ts">
<violation number="1" location="packages/opencode/src/provider/error.ts:120">
P2: Codes above 599 are not 5xx, but this condition marks every numeric code ≥500 as retryable and sends it through the session retry loop. Restrict the check to integer codes from 500 through 599.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| responseBody, | ||
| } | ||
| } | ||
| if (typeof body.code === "number" && body.code >= 500) { |
There was a problem hiding this comment.
P2: Codes above 599 are not 5xx, but this condition marks every numeric code ≥500 as retryable and sends it through the session retry loop. Restrict the check to integer codes from 500 through 599.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/opencode/src/provider/error.ts, line 120:
<comment>Codes above 599 are not 5xx, but this condition marks every numeric code ≥500 as retryable and sends it through the session retry loop. Restrict the check to integer codes from 500 through 599.</comment>
<file context>
@@ -117,6 +117,14 @@ export function parseStreamError(input: unknown): ParsedStreamError | undefined
responseBody,
}
}
+ if (typeof body.code === "number" && body.code >= 500) {
+ return {
+ type: "api_error",
</file context>
Suggested change
| if (typeof body.code === "number" && body.code >= 500) { | |
| if (typeof body.code === "number" && Number.isInteger(body.code) && body.code >= 500 && body.code < 600) { |
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.
Description
Follow-up to #43 (USE-2673). That PR handled the one typeless OpenRouter chunk that meant context overflow. OpenRouter uses the same shape for every relayed upstream failure, and in the last 30 days production saw three more of them, each ending a turn as a non-retryable
UnknownError:{ "code": 502, "message": "Stream ended before a terminal response event", "metadata": { "error_type": "provider_unavailable" } } { "code": 503, "message": "upstream connect error or disconnect/reset before headers. reset reason: connection timeout" } { "code": 504, "message": "Upstream idle timeout exceeded", "metadata": { "error_type": "timeout" } }These are transient provider failures. The session retry loop already retries any
APIErrormarked retryable or carrying a 5xx status, butparseStreamErrornever produced one for a body withouttype: "error".This PR adds one rule after the overflow check: a typeless body whose numeric
codeis 5xx becomes a retryableAPIErrorcarrying the provider's message. The overflow rule stays first so an overflow 502 still compacts rather than retries.Not shipped to the fleet until a release tag and an
OPENCODE_VERSIONbump in andytown.Testing
bun test test/session/message-v2.test.ts: 38 pass, including the new case feeding the exact production 502 chunk throughfromErrorand expecting a retryableAPIError.bun run typecheckinpackages/opencode: clean.🤖 Generated with Claude Code
Summary by cubic
Classifies OpenRouter's typeless 5xx chunks as retryable
APIErrorso transient provider failures no longer end turns as non-retryableUnknownError.Bug Fixes
parseStreamErrornow turns any typeless body with a numeric 5xxcodeinto a retryableAPIErrorcarrying the provider's message.OPENCODE_VERSIONbump in andytown.Written for commit 15eddc8. Summary will update on new commits.