Repository navigation
Conversation
Only 429 was retried, after a fixed 1s/2s pause. An overloaded (529) response went straight back to the caller, and a 429's Retry-After was ignored: a short one was retried too early, and a usage-limit one that resets in hours was retried twice for nothing. Retry 429 and 529 up to twice, waiting as long as Retry-After asks (exponential backoff when it is absent). A wait longer than 10s is not absorbed inside the request: the response is returned at once, so opencode's own retry loop - which shows the wait and can be cancelled - takes over. The wait ends early when the request is aborted, and the failed response body is released before the retry. 429 keeps its token refresh.
The token request retried only 429. An overloaded (529) answer failed the refresh at once, and when 429 retries ran out the caller got a made-up "Rate limited" response instead of what the endpoint actually said. Retry 529 as well, wait as long as the body's retry_after asks, and return the endpoint's real last answer. The request blocks the process while it sleeps, so a requested wait over 10s is not absorbed: the answer is returned straight away.
The Messages API takes `system` either as a string or as text blocks, but the request rewrite assumed blocks. A string made it throw before the billing header was added; the error was swallowed and the request went out unrewritten, so the subscription endpoint rejected it. Wrap a string prompt in a single text block before rewriting.
When a request fails, opencode shows a one-line summary and the error body and request id are gone, which is exactly what is needed to tell a rejected request shape from a rate limit or an outage. Write each failed response that is handed back to opencode (after any retries) to stderr and append it, with its request id, to opencode/log/claude-bridge-api-errors.log under XDG_DATA_HOME (~/.local/share by default), next to opencode's own logs.
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.
Summary
Retry-Afterasks (exponential backoff when it is absent). Before, only 429 was retried, after a fixed 1s/2s pause, and a 529 went straight back to opencode. A requested wait longer than 10s is not absorbed inside the request: the response is returned at once so opencode's own retry loop — which shows the wait and can be cancelled — takes over, instead of a usage-limit 429 that resets in hours being retried twice for nothing. The wait ends early when the request is aborted, and 429 keeps its token refresh.retry_afterfrom its body, and return the endpoint's real last answer instead of a made-up "Rate limited" 429.systemprompt. The request rewrite assumed text blocks; a string threw before the billing header was added, the error was swallowed, and the request went out unrewritten.~/.local/share/opencode/log/claude-bridge-api-errors.log($XDG_DATA_HOMEis respected).Test plan
npm test— retry policy units; the plugin's fetch wrapper driven against a stubbed network (529 recovery, retries running out, longRetry-After, abort during the wait, stringsystemprompt, error log); the token endpoint retry loop driven through a stand-incurlnpm run typecheck