Răsfoiți Sursa

fix(session): retry 5xx server errors even when isRetryable is unset (#22511)

Kit Langton 1 săptămână în urmă
părinte
comite
4ca809ef4e

+ 4 - 1
packages/opencode/src/session/retry.ts

@@ -56,7 +56,10 @@ export namespace SessionRetry {
     // context overflow errors should not be retried
     if (MessageV2.ContextOverflowError.isInstance(error)) return undefined
     if (MessageV2.APIError.isInstance(error)) {
-      if (!error.data.isRetryable) return undefined
+      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.responseBody?.includes("FreeUsageLimitError")) return GO_UPSELL_MESSAGE
       return error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message
     }

+ 41 - 0
packages/opencode/test/session/retry.test.ts

@@ -178,6 +178,47 @@ describe("session.retry.retryable", () => {
     expect(SessionRetry.retryable(error)).toBeUndefined()
   })
 
+  test("retries 500 errors even when isRetryable is false", () => {
+    const error = new MessageV2.APIError({
+      message: "Internal server error",
+      isRetryable: false,
+      statusCode: 500,
+      responseBody: '{"type":"api_error","message":"Internal server error"}',
+    }).toObject() as MessageV2.APIError
+
+    expect(SessionRetry.retryable(error)).toBe("Internal server error")
+  })
+
+  test("retries 502 bad gateway errors", () => {
+    const error = new MessageV2.APIError({
+      message: "Bad gateway",
+      isRetryable: false,
+      statusCode: 502,
+    }).toObject() as MessageV2.APIError
+
+    expect(SessionRetry.retryable(error)).toBe("Bad gateway")
+  })
+
+  test("retries 503 service unavailable errors", () => {
+    const error = new MessageV2.APIError({
+      message: "Service unavailable",
+      isRetryable: false,
+      statusCode: 503,
+    }).toObject() as MessageV2.APIError
+
+    expect(SessionRetry.retryable(error)).toBe("Service unavailable")
+  })
+
+  test("does not retry 4xx errors when isRetryable is false", () => {
+    const error = new MessageV2.APIError({
+      message: "Bad request",
+      isRetryable: false,
+      statusCode: 400,
+    }).toObject() as MessageV2.APIError
+
+    expect(SessionRetry.retryable(error)).toBeUndefined()
+  })
+
   test("retries ZlibError decompression failures", () => {
     const error = new MessageV2.APIError({
       message: "Response decompression failed",