summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAiden Cline <[email protected]>2026-04-23 17:31:43 -0400
committerGitHub <[email protected]>2026-04-23 17:31:43 -0400
commit334ab4707c809172e77619ae7d6b22c5577c7238 (patch)
tree4953fab15f1e49a48864b3afb0f0d6e90d4ddcfa
parent87321942fee25786448f02284ebeaee1caf4e86c (diff)
downloadopencode-334ab4707c809172e77619ae7d6b22c5577c7238.tar.gz
opencode-334ab4707c809172e77619ae7d6b22c5577c7238.zip
fix: account for additional openai retry case (#24063)
-rw-r--r--packages/opencode/src/provider/error.ts12
-rw-r--r--packages/opencode/test/session/message-v2.test.ts24
-rw-r--r--packages/opencode/test/session/retry.test.ts22
3 files changed, 56 insertions, 2 deletions
diff --git a/packages/opencode/src/provider/error.ts b/packages/opencode/src/provider/error.ts
index a2409559f..a4f629caf 100644
--- a/packages/opencode/src/provider/error.ts
+++ b/packages/opencode/src/provider/error.ts
@@ -111,12 +111,13 @@ export type ParsedStreamError =
| {
type: "api_error"
message: string
- isRetryable: false
+ isRetryable: boolean
responseBody: string
}
export function parseStreamError(input: unknown): ParsedStreamError | undefined {
- const body = json(input)
+ const raw = json(input)
+ const body = typeof raw?.message === "string" ? (json(raw.message) ?? raw) : raw
if (!body) return
const responseBody = JSON.stringify(body)
@@ -150,6 +151,13 @@ export function parseStreamError(input: unknown): ParsedStreamError | undefined
isRetryable: false,
responseBody,
}
+ case "server_error":
+ return {
+ type: "api_error",
+ message: typeof body?.error?.message === "string" ? body?.error?.message : "Server error.",
+ isRetryable: true,
+ responseBody,
+ }
}
}
diff --git a/packages/opencode/test/session/message-v2.test.ts b/packages/opencode/test/session/message-v2.test.ts
index 231d58c21..abada013d 100644
--- a/packages/opencode/test/session/message-v2.test.ts
+++ b/packages/opencode/test/session/message-v2.test.ts
@@ -1075,6 +1075,30 @@ describe("session.message-v2.fromError", () => {
})
})
+ test("serializes OpenAI response server_error stream chunks as retryable APIError", () => {
+ const body = {
+ type: "error",
+ sequence_number: 2,
+ error: {
+ type: "server_error",
+ code: "server_error",
+ message:
+ "An error occurred while processing your request. You can retry your request, or contact us through our help center at help.openai.com if the error persists. Please include the request ID req_77eccd008d984bf6bf82d1b2c2b68715 in your message.",
+ param: null,
+ },
+ }
+ const result = MessageV2.fromError({ message: JSON.stringify(body) }, { providerID })
+
+ expect(result).toStrictEqual({
+ name: "APIError",
+ data: {
+ message: body.error.message,
+ isRetryable: true,
+ responseBody: JSON.stringify(body),
+ },
+ })
+ })
+
test("detects context overflow from APICallError provider messages", () => {
const cases = [
"prompt is too long: 213462 tokens > 200000 maximum",
diff --git a/packages/opencode/test/session/retry.test.ts b/packages/opencode/test/session/retry.test.ts
index ade264786..6ca8775f3 100644
--- a/packages/opencode/test/session/retry.test.ts
+++ b/packages/opencode/test/session/retry.test.ts
@@ -294,4 +294,26 @@ describe("session.message-v2.fromError", () => {
const result = MessageV2.fromError(error, { providerID: ProviderID.make("openai") }) as MessageV2.APIError
expect(result.data.isRetryable).toBe(true)
})
+
+ test("converts OpenAI server_error stream chunks to retryable APIError", () => {
+ const result = MessageV2.fromError(
+ {
+ message: JSON.stringify({
+ type: "error",
+ sequence_number: 2,
+ error: {
+ type: "server_error",
+ code: "server_error",
+ message: "An error occurred while processing your request.",
+ param: null,
+ },
+ }),
+ },
+ { providerID: ProviderID.make("openai") },
+ )
+
+ expect(MessageV2.APIError.isInstance(result)).toBe(true)
+ expect((result as MessageV2.APIError).data.isRetryable).toBe(true)
+ expect(SessionRetry.retryable(result)).toBe("An error occurred while processing your request.")
+ })
})