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

  1. No fix needed if the abort was intentional — treat ToolAbortError as normal cancellation and stop retrying.
  2. If aborts happen unintentionally, check upstream wiring that shares one AbortSignal across many tool calls.
  3. Reduce render latency by reusing a warm browser so renders complete before the user cancels.
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/a3b2cd886e8a20ba. Report an issue: GitHub.