can1357/oh-my-pi · info · ToolAbortError
ToolAbortError (operation aborted)
Error message
ToolAbortError (operation aborted)
What it means
renderPdfPageScreenshot renders a single PDF page to a screenshot by loading it in a headless Chromium tab. When the caller-supplied AbortSignal (the tool call's cancellation signal) fires before rendering completes, the catch block rethrows as ToolAbortError ('operation aborted') instead of the underlying error. This signals orderly cancellation, not a failure of the renderer itself.
Source
Thrown at packages/coding-agent/src/tools/read-pdf.ts:131
signal: renderSignal,
ownerSessionId: session.getSessionId?.() ?? undefined,
}),
);
tabOpened = true;
await releaseBrowser(acquiredBrowser, { kill: false });
browserLease = false;
const result = await runInTab(tabName, {
code: PDF_SCREENSHOT_CODE,
timeoutMs: PDF_RENDER_TIMEOUT_MS,
signal: renderSignal,
session,
});
const screenshot = result.screenshots.at(-1);
if (!screenshot) throw new ToolError(`Chromium did not capture PDF page ${page}.`);
return screenshot;
} catch (error) {
if (signal?.aborted) throw new ToolAbortError();
if (timeoutSignal.aborted) {
throw new ToolError(`Timed out rendering PDF page ${page} in Chromium.`);
}
throw error;
} finally {
if (tabOpened) await releaseTab(tabName, { kill: false });
if (browserLease && browser) await releaseBrowser(browser, { kill: false });
}
}
View on GitHub (pinned to 9690622007)
Solutions
- No fix needed if the abort was intentional — treat ToolAbortError as normal cancellation and stop retrying.
- If aborts happen unintentionally, check upstream wiring that shares one AbortSignal across many tool calls.
- Reduce render latency by reusing a warm browser so renders complete before the user cancels.
- Check that the cancellation UI doesn't fire spuriously (e.g. short client timeouts).
Example fix
// before: treating abort as a crash
try { shot = await renderPdfPageScreenshot(...) } catch (e) { log(e); }
// after
try { shot = await renderPdfPageScreenshot(...) }
catch (e) { if (e instanceof ToolAbortError) return; /* user cancelled */ throw e; } Defensive patterns
Strategy: try-catch
Validate before calling
// before calling if (signal?.aborted) return; // don't start work already cancelled
Type guard
function isToolAbortError(e: unknown): boolean {
return e instanceof Error && e.name === 'ToolAbortError';
} Try / catch
try {
const shot = await renderPdfPageScreenshot(session, pdfPath, page, signal);
} catch (e) {
if (isToolAbortError(e)) return; // expected cancellation, not a failure
throw e;
} Prevention
- Pass the caller's AbortSignal through so cancellation is recognized, not masked.
- Treat ToolAbortError as control flow: swallow or propagate silently, never retry.
- Keep renders fast (warm browser) so users rarely need to cancel mid-render.
- Never wrap aborts in generic retry loops — retrying an aborted call loops forever.
When it happens
Trigger: The user cancels the tool call (Esc / abort) while Chromium is acquiring the browser, opening the PDF tab, or running PDF_SCREENSHOT_CODE in the tab; renderSignal = AbortSignal.any([signal, timeoutSignal]) propagates the abort and the catch checks signal?.aborted first.
Common situations: User interrupts a slow PDF read; an orchestration layer cancels the agent turn mid-render; a long browser-acquisition queue (cold Chromium startup) makes the user give up before the render finishes.
Related errors
- Request was aborted
- Auth broker request aborted
- OAuth refresh ownership aborted by caller
- Request was aborted.
- AbortError
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a3b2cd886e8a20ba.
Report an issue: GitHub.