fix(opencode): expand retryable error patterns (#40707)

This commit is contained in:
Aiden Cline
2026-08-05 14:39:49 -05:00
committed by GitHub
parent f929f8f100
commit 61aefc0759
2 changed files with 59 additions and 9 deletions
+20 -9
View File
@@ -28,6 +28,15 @@ export const RETRY_BACKOFF_FACTOR = 2
export const RETRY_MAX_DELAY_NO_HEADERS = 30_000 // 30 seconds
export const RETRY_MAX_DELAY = 2_147_483_647 // max 32-bit signed integer for setTimeout
const RETRYABLE_MESSAGE_PATTERNS = [
/429|500|502|503|504|524/i,
/rate increased too quickly|rate limit|rate-limit|rate_limit|too many requests/i,
/overloaded|service unavailable|service_unavailable|service-unavailable|internal error|internal_error|internal server error|server error|server_error|server-error|provider returned error|provider_returned_error|provider-returned-error/i,
/terminated|fetch failed|failed to fetch|network error|upstream connect|connection error|connection refused|connection lost|socket connection was closed|socket hang up|reset before headers|getaddrinfo|enotfound|eai_again|econnrefused|econnreset|etimedout/i,
/^timeout$|\b(?:request|response|connection|network|stream|read) (?:timeout|timed out|time out)\b/i,
/try your request again|retry your request|resource exhausted|resource_exhausted/i,
]
function cap(ms: number) {
return Math.min(ms, RETRY_MAX_DELAY)
}
@@ -72,7 +81,12 @@ export function retryable(error: Err, provider: string) {
const status = error.data.statusCode
// 5xx errors are transient server failures and should always be retried,
// even when the provider SDK doesn't explicitly mark them as retryable.
if (!error.data.isRetryable && !(status !== undefined && status >= 500)) return undefined
if (
!error.data.isRetryable &&
!(status !== undefined && status >= 500) &&
!matchesRetryableMessage(error.data.message) &&
!matchesRetryableMessage(error.data.responseBody)
) return undefined
if (error.data.responseBody?.includes("FreeUsageLimitError")) {
return {
message: GO_UPSELL_MESSAGE,
@@ -125,19 +139,16 @@ export function retryable(error: Err, provider: string) {
const message = isRecord(error.data) ? error.data.message : undefined
if (typeof message !== "string") return undefined
const lower = message.toLowerCase()
if (
lower.includes("rate increased too quickly") ||
lower.includes("rate limit") ||
lower.includes("rate_limit") ||
lower.includes("too many requests")
) {
return { message }
}
if (lower.includes("too_many_requests")) return { message: "Too Many Requests" }
if (lower.includes("exhausted") || lower.includes("unavailable")) return { message: "Provider is overloaded" }
if (matchesRetryableMessage(message)) return { message }
return undefined
}
function matchesRetryableMessage(value: unknown) {
return typeof value === "string" && RETRYABLE_MESSAGE_PATTERNS.some((pattern) => pattern.test(value))
}
function str(value: unknown) {
if (value === undefined || value === null) return ""
return String(value)