Skip to content

Commit 6c86773

Browse files
committed
fix: retry on timeout errors instead of failing
AbortSignal.timeout() throws DOMException with name 'TimeoutError', which was not handled in fromError(). This caused timeout errors to become Unknown errors (not retryable), stopping the session instead of retrying. Now timeout errors are converted to APIError with isRetryable: true, enabling automatic retry with exponential backoff. Fixes #13138 Signed-off-by: Mörgæsis <morgaesis+git@morgaes.is>
1 parent 8043cfa commit 6c86773

2 files changed

Lines changed: 16 additions & 0 deletions

File tree

packages/opencode/src/session/message-v2.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,14 @@ export function fromError(
971971
cause: e,
972972
},
973973
).toObject()
974+
case e instanceof DOMException && e.name === "TimeoutError":
975+
return new APIError(
976+
{
977+
message: e.message || "Operation timed out",
978+
isRetryable: true,
979+
},
980+
{ cause: e },
981+
).toObject()
974982
case OutputLengthError.isInstance(e):
975983
return e
976984
case LoadAPIKeyError.isInstance(e):

packages/opencode/test/session/message-v2.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,14 @@ describe("session.message-v2.toModelMessage", () => {
950950
})
951951

952952
describe("session.message-v2.fromError", () => {
953+
test("classifies timeout DOMException as retryable APIError", () => {
954+
const result = MessageV2.fromError(new DOMException("operation timed out", "TimeoutError"), { providerID })
955+
956+
expect(MessageV2.APIError.isInstance(result)).toBe(true)
957+
expect((result as MessageV2.APIError).data.message).toBe("operation timed out")
958+
expect((result as MessageV2.APIError).data.isRetryable).toBe(true)
959+
})
960+
953961
test("serializes context_length_exceeded as ContextOverflowError", () => {
954962
const input = {
955963
type: "error",

0 commit comments

Comments
 (0)