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
- Retry the read — a warm browser usually renders well within the timeout.
- Pre-warm the headless browser before batch PDF processing.
- Verify Chromium is installed/downloaded locally so startup isn't dominated by download.
- Check machine CPU/memory pressure; headless rendering is CPU-bound.
- 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
- Pre-warm the headless browser before processing many PDFs.
- Avoid first-run environments where Chromium must be downloaded on demand.
- Render on a machine with adequate CPU/RAM; headless rendering is CPU-bound.
- Split huge PDFs; render fewer pages per call.
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
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timed out waiting for CDP endpoint ${cdpUrl}${lastStatus !==
- tab.waitForUrl() timed out after ${timeoutMs}ms
- tab.waitForNavigation() timed out after ${timeoutMs}ms
- tab.waitForResponse() timed out after ${timeoutMs}ms
- page.waitForFunction() timed out after ${timeoutMs}ms
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3b2b22ed1ac80555.
Report an issue: GitHub.