can1357/oh-my-pi · warning · ToolAbortError
Aborted
Error message
Aborted
What it means
readResponseWithLimit streams the response body chunk-by-chunk and checks the AbortSignal before every read. When the signal is aborted it cancels the reader and throws ToolAbortError('Aborted') so body reads don't hang past cancellation. This propagates the caller's cancellation into the body-streaming phase.
Source
Thrown at packages/coding-agent/src/web/scrapers/utils.ts:42
ok: true;
buffer: Uint8Array;
contentDisposition?: string;
}
export type BinaryFetchResult = BinaryFetchSuccess | { ok: false; error?: string };
async function readResponseWithLimit(response: Response, maxBytes: number, signal?: AbortSignal): Promise<Uint8Array> {
const reader = response.body?.getReader();
if (!reader) return new Uint8Array(0);
const chunks: Buffer[] = [];
let totalBytes = 0;
try {
while (true) {
if (signal?.aborted) {
await reader.cancel();
throw new ToolAbortError();
}
const { done, value } = await reader.read();
if (done) break;
if (!value || value.byteLength === 0) continue;
totalBytes += value.byteLength;
if (totalBytes > maxBytes) {
await reader.cancel();
throw new Error(`response exceeds ${maxBytes} bytes`);
}
chunks.push(Buffer.from(value));
}
} finally {
reader.releaseLock();
}
return new Uint8Array(Buffer.concat(chunks, totalBytes));View on GitHub (pinned to 9690622007)
Solutions
- Raise the caller's timeout if large payloads legitimately take long.
- Catch ToolAbortError around readResponseWithLimit/fetchBinary and treat as cancellation.
- Verify upstream code isn't aborting early (e.g. a race with an already-resolved promise).
- Pass undefined signal only if you truly want an unabortable read — otherwise keep the signal and handle the error.
Example fix
// before
const buf = await readResponseWithLimit(res, MAX, signal);
// after
let buf;
try { buf = await readResponseWithLimit(res, MAX, signal); }
catch (e) { if (e instanceof ToolAbortError) return { ok: false, error: "aborted" }; throw e; } Defensive patterns
Strategy: try-catch
Validate before calling
// Nothing to pre-validate; optionally abort early:
if (signal?.aborted) return { ok: false, error: "aborted" }; Type guard
import { ToolAbortError } from "../tools/tool-errors"; const isToolAbortError = (e: unknown): e is ToolAbortError => e instanceof ToolAbortError; Try / catch
try { const buf = await readResponseWithLimit(res, MAX, signal); }
catch (e) {
if (isToolAbortError(e)) return { ok: false, error: "aborted" };
if (e instanceof Error && /response exceeds/.test(e.message)) return { ok: false, error: "too-large" };
throw e;
} Prevention
- Keep the AbortSignal threaded through body reads, not just the fetch call.
- Handle abort distinctly from size-limit errors — they share the code path but mean different things.
- For big payloads, prefer Content-Length pre-checks over discovering overflow mid-stream.
When it happens
Trigger: AbortSignal fires while the response body is still being streamed into the size-capped reader loop — the next loop iteration detects signal.aborted.
Common situations: Large/slow downloads (PDFs, images) cancelled by a tool timeout or user abort halfway through the body.
Related errors
- Request was aborted
- Auth broker request aborted
- AbortError
- AbortError
- OAuth refresh ownership aborted by caller
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a916ba4b7371924b.
Report an issue: GitHub.