can1357/oh-my-pi · error · ToolError

Timed out rendering PDF page ${page} in Chromium.

Error message

Timed out rendering PDF page ${page} in Chromium.

What it means

renderPdfPageScreenshot enforces PDF_RENDER_TIMEOUT_MS via AbortSignal.timeout. If acquiring Chromium, opening the PDF tab, or running the screenshot code exceeds that budget, the catch block detects timeoutSignal.aborted and throws a ToolError 'Timed out rendering PDF page N in Chromium.' It means the headless browser pipeline did not produce a capture in time.

Source

Thrown at packages/coding-agent/src/tools/read-pdf.ts:133

			}),
		);
		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. Retry the read — a warm browser usually renders well within the timeout.
  2. Pre-warm the headless browser before batch PDF processing.
  3. Verify Chromium is installed/downloaded locally so startup isn't dominated by download.
  4. Check machine CPU/memory pressure; headless rendering is CPU-bound.
  5. If it persists, split the PDF and read fewer/smaller pages per call.

Example fix

// before: unbounded single attempt
const shot = await renderPdfPageScreenshot(session, pdfPath, page);
// after: warm retry
try { shot = await renderPdfPageScreenshot(session, pdfPath, page); }
catch (e) {
  if (String(e).includes('Timed out rendering PDF page')) {
    await warmBrowser(session); // second attempt reuses warm browser
    shot = await renderPdfPageScreenshot(session, pdfPath, page);
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: ensure a browser is available before the timed render
const browser = await acquireBrowser({ kind: 'headless', headless: true }, { cwd, signal });
await releaseBrowser(browser, { kill: false }); // warm the registry

Try / catch

try {
  return await renderPdfPageScreenshot(session, pdfPath, page, signal);
} catch (e) {
  if (e instanceof ToolError && /Timed out rendering PDF page/.test(e.message)) {
    await Bun.sleep(500); // warm browser, then one retry
    return await renderPdfPageScreenshot(session, pdfPath, page, signal);
  }
  throw e;
}

Prevention

When it happens

Trigger: Cold Chromium download/startup takes too long; the PDF viewer page never reaches 'load'; the PDF page is huge/complex so the screenshot script runs past PDF_RENDER_TIMEOUT_MS; acquireTab's shared deadline (deadlineStartMs) is exhausted.

Common situations: First-ever PDF read in an environment where Chromium must be fetched; slow or resource-starved CI containers; very large scanned PDFs; browser registry contention delaying acquisition.

Understand the failure class

Related errors


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