From 7f4f322c7385049dcc1c12e06faad0a1632c28c4 Mon Sep 17 00:00:00 2001 From: roboomp Date: Mon, 27 Jul 2026 18:19:38 +0000 Subject: [PATCH] fix(cli): wrap streaming-phase download timeout with friendly message downloadVerifiedBinary only wrapped isTimeoutError around the fetch() catch, so a 15-minute timeout firing while pipeline() streamed the response body re-threw the raw "TimeoutError: The operation timed out." Mirror the wrap into the pipeline catch after cleaning up the partial file, matching the connection-phase message. Fixes #6822 --- packages/coding-agent/CHANGELOG.md | 4 +++ packages/coding-agent/src/cli/update-cli.ts | 3 +++ packages/coding-agent/test/update-cli.test.ts | 25 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 280be8c1e..24402acf5 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed `omp update` surfacing a raw `TimeoutError: The operation timed out.` when the 15-minute download deadline fired while streaming the binary body rather than during the initial `fetch()`. The streaming-phase catch now emits the same friendly `Timed out downloading release binary after 15 minutes` message as the connection phase ([#6822](https://github.com/can1357/oh-my-pi/issues/6822)). + ## [17.1.6] - 2026-07-27 ### Added diff --git a/packages/coding-agent/src/cli/update-cli.ts b/packages/coding-agent/src/cli/update-cli.ts index e86d22782..3b87fc6b0 100644 --- a/packages/coding-agent/src/cli/update-cli.ts +++ b/packages/coding-agent/src/cli/update-cli.ts @@ -231,6 +231,9 @@ export async function downloadVerifiedBinary(options: VerifiedBinaryDownloadOpti await fs.promises.chmod(options.targetPath, 0o755); } catch (err) { await unlinkIfExists(options.targetPath); + if (isTimeoutError(err)) { + throw new Error("Timed out downloading release binary after 15 minutes", { cause: err }); + } throw err; } } diff --git a/packages/coding-agent/test/update-cli.test.ts b/packages/coding-agent/test/update-cli.test.ts index 88df3a3fb..c232253c4 100644 --- a/packages/coding-agent/test/update-cli.test.ts +++ b/packages/coding-agent/test/update-cli.test.ts @@ -465,6 +465,31 @@ describe("update-cli release binary integrity", () => { expect(await Bun.file(targetPath).exists()).toBe(false); }); + it("wraps a timeout during body streaming with a friendly message", async () => { + const dir = await makeTempDir(); + const targetPath = path.join(dir, binaryName); + const body = new ReadableStream( + { + pull(controller) { + controller.enqueue(new Uint8Array(1)); + controller.error(new DOMException("The operation timed out.", "TimeoutError")); + }, + }, + { highWaterMark: 0 }, + ); + + await expect( + downloadVerifiedBinary({ + url, + targetPath, + expectedSize: Buffer.byteLength(content), + expectedDigest: digest, + fetchImpl: async () => new Response(body), + }), + ).rejects.toThrow("Timed out downloading release binary after 15 minutes"); + expect(await Bun.file(targetPath).exists()).toBe(false); + }); + it("removes downloads whose size or digest does not match", async () => { const dir = await makeTempDir(); const targetPath = path.join(dir, binaryName);