puppeteer
semver
>=1.0.0postconditions19functions19last verified2026-06-23coverage score100%Postconditions: what we check
- launch · launch-rejects-on-errorerrorWhenbrowser launch fails (timeout, protocol error, missing Chrome)Throws
Promise rejection with TimeoutError, ProtocolError, or ErrorRequired handlingCaller MUST use try-catch to handle Promise rejections from puppeteer.launch(). Common failures: timeout (default 30s), protocol errors in Docker/containers, missing Chrome binary. Browser instance MUST be closed in finally block to prevent zombie processes. Use pattern: let browser; try { browser = await puppeteer.launch(); } catch (error) { /* handle */ } finally { if (browser) await browser.close(); }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - goto · goto-rejects-on-timeouterrorWhennavigation timeout (default 30s) or network errorThrows
Promise rejection with TimeoutErrorRequired handlingCaller MUST use try-catch to handle Promise rejections from page.goto(). This is the #1 cause of production failures. Timeouts occur with slow networks, Cloudflare protection, heavy JavaScript pages. CRITICAL: In headless shell mode, HTTP 404/500 do NOT throw - must check response.ok(). Use pattern: const response = await page.goto(url, { timeout: 60000 }); if (!response || !response.ok()) throw new Error('Navigation failed');costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - newPage · newpage-rejects-on-errorerrorWhenpage creation timeout or protocol errorThrows
Promise rejection with ProtocolError (Target.createTarget timed out)Required handlingCaller MUST use try-catch to handle Promise rejections from browser.newPage(). Common in Docker/containers with rapid page creation cycles. Increase protocolTimeout in launch options for containers. Use pattern: try { const page = await browser.newPage(); } catch (error) { /* handle */ }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - close · browser-close-must-runwarningWhenbrowser instance exists after operationsThrows
May throw Error if browser already closed or connection lostRequired handlingBrowser.close() MUST be called in finally block to prevent zombie Chrome processes. Each zombie process consumes 80-90MB. Accumulation causes memory exhaustion and server crashes. Close can itself throw errors - wrap in try-catch within finally to avoid masking original errors. Use pattern: finally { if (browser) { try { await browser.close(); } catch (e) {} } }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4] - waitForSelector · waitforselector-rejects-on-timeoutwarningWhenelement not found within timeout (default 30s)Throws
Promise rejection with TimeoutErrorRequired handlingCaller MUST use try-catch to handle TimeoutError from page.waitForSelector(). Timeouts common when element never appears or takes longer than expected. Consider increasing timeout for slow-loading pages. Use pattern: try { await page.waitForSelector('selector', { timeout: 10000 }); } catch (error) { /* handle */ }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[5] - click · click-rejects-on-errorwarningWhenelement not found or not clickableThrows
Promise rejection with ErrorRequired handlingCaller MUST use try-catch to handle errors from page.click(). Common failures: selector not found, element not clickable, element moved. CRITICAL: When click triggers navigation, use Promise.all([page.waitForNavigation(), page.click()]) to avoid race conditions. Use pattern: try { await page.click('button'); } catch (error) { /* handle */ }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[6] - evaluate · evaluate-execution-errorerrorWhenJavaScript execution fails in page context (page closed, navigation during eval, unserializable return)Throws
TargetCloseError if page navigated/closed during evaluation, Error if function throws in browser contextRequired handlingCaller MUST wrap page.evaluate() in try-catch. Common failures: (1) Page navigated away during evaluation — throws TargetCloseError. (2) Function throws in browser context — error propagated to Node.js. (3) Return value not serializable — throws Error. (4) Execution context destroyed (SPA navigation) — throws ProtocolError. In scraping/automation pipelines, evaluate() failures are the #1 cause of silent data loss — the scrape returns undefined instead of crashing.costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[7] - screenshot · screenshot-protocol-errorerrorWhenScreenshot capture fails (page closed, protocol error, invalid options)Throws
TargetCloseError if page closed during capture, Error on invalid crop/options, ProtocolError on CDP failureRequired handlingCaller MUST wrap page.screenshot() in try-catch. Failures include: (1) Page navigated/closed during capture — TargetCloseError. (2) Invalid crop dimensions (negative, exceeds viewport) — throws Error. (3) fullPage screenshot of infinite-scroll pages — may cause OOM. (4) ProtocolError when page is mid-navigation. CRITICAL: In image generation services, unhandled screenshot errors return empty/corrupt images to users without alerting.costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[8] - pdf · pdf-headless-only-errorerrorWhenpdf() called in headed (non-headless) browser modeThrows
Error indicating PDF generation only works in headless modeRequired handlingCaller MUST wrap page.pdf() in try-catch. Key failure modes: (1) Called in headed mode — throws immediately. (2) Page navigated/closed during generation — TargetCloseError. (3) ProtocolError on CDP failure during rendering. CRITICAL: PDF generation services that don't catch errors return empty PDFs or crash the worker process. Always verify the returned buffer has non-zero length before serving to users.costhighin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[9] - setContent · setcontent-timeout-errorerrorWhenPage content loading exceeds timeout (default 30s)Throws
TimeoutError when waitUntil condition not met within timeoutRequired handlingCaller MUST wrap page.setContent() in try-catch. setContent() waits for the page to reach the specified load state (default: 'load'). Complex HTML with external resources can timeout. In HTML-to-PDF pipelines, timeout on setContent silently aborts the generation. Set explicit timeout and handle: page.setContent(html, { timeout: 60000 }).costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[10] - waitForNavigation · waitfornavigation-timeout-errorerrorWhenNavigation does not complete within timeout (default 30s)Throws
TimeoutError when navigation exceeds timeout, TargetCloseError if page closes during waitRequired handlingCaller MUST wrap page.waitForNavigation() in try-catch. This is the most common source of flaky Puppeteer tests and production failures. Key patterns: (1) Must be called BEFORE the action that triggers navigation — use Promise.all([page.waitForNavigation(), page.click()]). (2) SPA route changes may resolve with null response. (3) Multiple rapid navigations cause race conditions. (4) Timeout in CI/Docker environments due to slow rendering.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[11] - waitForNetworkIdle · waitfornetworkidle-timeout-errorwarningWhenNetwork does not become idle within timeoutThrows
TimeoutError when network remains active past timeout, TargetCloseError if page closesRequired handlingCaller MUST wrap page.waitForNetworkIdle() in try-catch. Common failures: (1) Pages with persistent WebSocket/SSE connections never reach idle — timeout guaranteed. (2) Analytics/tracking scripts continually fire requests. (3) Long-polling APIs keep network busy. Always set an explicit timeout and handle TimeoutError gracefully rather than treating it as a hard failure.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[12] - waitForFunction · waitforfunction-timeout-errorwarningWhenFunction does not return truthy value within timeoutThrows
TimeoutError when condition not met within timeout, TargetCloseError if page closes during waitRequired handlingCaller MUST wrap page.waitForFunction() in try-catch. Timeout occurs when the evaluated function never returns truthy. Common in scraping when waiting for dynamic content that may not appear. The function re-evaluates on every animation frame or on DOM mutation (depending on polling option), so infinite loops in the function will not throw — they just timeout silently.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[13] - type · type-element-not-foundwarningWhenTarget element selector not found on pageThrows
Error when no element matches the provided selectorRequired handlingCaller MUST wrap page.type() in try-catch. The method throws if the selector does not match any element. Common in form automation when pages load dynamically — always waitForSelector() before type(). Also throws TargetCloseError if page navigates during typing (e.g., auto-submit forms).costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[14] - $eval · eval-element-not-founderrorWhenNo element matches the provided selectorThrows
Error indicating no element found for selectorRequired handlingCaller MUST wrap page.$eval() in try-catch. Unlike page.$() which returns null when no element is found, $eval() THROWS an error. This is a critical distinction — code that works with $() will crash with $eval() on missing elements. Use page.$() first to check existence, or wrap in try-catch. Common in scraping when page structure varies across different pages.costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[15] - connect · connect-websocket-errorerrorWhenWebSocket connection to browser fails (wrong URL, browser not running, network error)Throws
Error on WebSocket connection failure, TimeoutError if connection times outRequired handlingCaller MUST wrap puppeteer.connect() in try-catch. Connection failures common with: (1) Browser process crashed/exited before connect. (2) Wrong WebSocket URL (port changed, container restarted). (3) Network partition between Puppeteer and remote browser. CRITICAL: In browser pool architectures, connect() failures without error handling cause the entire worker to crash instead of gracefully acquiring a new browser.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[16] - executablePath · executablepath-async-rejectionerrorWhenUnderlying launcher cannot resolve a browser binary for the host (binary missing from cache, platform unsupported, channel not installed)Throws
Promise rejection with Error when the launcher's executablePath resolution fails (e.g. unknown ChromeReleaseChannel, no binary cached, unsupported platform)Required handlingCaller MUST wrap puppeteer.executablePath() in try-catch. CRITICAL breaking change: was synchronous in puppeteer <=24.x, became async in v25.0.0. Code that previously read the return value directly will now receive a Promise<string> and silently treat it as a path string like "[object Promise]" — passing it to spawn()/launch() fails with ENOENT. Callers that just upgraded to v25 MUST either await the result or use Promise.then. In CI/deployment scripts this is the #1 v25 migration footgun. Pattern: try { const path = await puppeteer.executablePath('chrome'); } catch (error) { /* handle */ }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - defaultArgs · defaultargs-async-rejectionerrorWhenBrowser launcher cannot resolve the requested browser (unknown browser type, lastLaunchedBrowser unresolvable for no-arg call)Throws
Promise rejection with Error when the underlying launcher cannot determine default argsRequired handlingCaller MUST wrap puppeteer.defaultArgs() in try-catch. Same v25.0.0 breaking change as executablePath() — was sync, now returns a Promise<string[]>. Code that does: const args = [...puppeteer.defaultArgs(), '--my-flag']; breaks silently on v25.x — spreading a Promise yields no array items and Chrome launches with only "--my-flag". Always await: const baseArgs = await puppeteer.defaultArgs(); const args = [...baseArgs, '--my-flag'];costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent - trimCache · trimcache-unsupported-platform-errorwarningWhenHost platform is not one of the platforms @puppeteer/browsers recognizes (e.g. exotic ARM64 Linux distros, unusual containers)Throws
Promise rejection with Error('The current platform is not supported.') OR Error from fs.rm on permission failures while pruning cache directoriesRequired handlingCaller MUST wrap puppeteer.trimCache() in try-catch. Two distinct failure modes: (1) platform detection fails — common in minimal containers without /etc/os-release or on uncommon ARM variants; (2) cache directory traversal hits a permission error (running as unprivileged user against a cache populated by root, or NFS-mounted cache with stale handles). In Docker build pipelines, an unhandled rejection here kills the whole build with no useful log line. Pattern: try { await puppeteer.trimCache(); } catch (error) { console.warn('trimCache skipped:', error); }costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[20]
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
Official documentation
- [1]pptr.dev/api/puppeteer.puppeteernode.launchPuppeteer.Puppeteernode.Launch
- [2]pptr.dev/api/puppeteer.page.gotoPuppeteer.Page.Goto
- [3]pptr.dev/api/puppeteer.browser.newpagePuppeteer.Browser.Newpage
- [4]pptr.dev/api/puppeteer.browser.closePuppeteer.Browser.Close
- [5]pptr.dev/api/puppeteer.page.waitforselectorPuppeteer.Page.Waitforselector
- [6]pptr.dev/api/puppeteer.page.clickPuppeteer.Page.Click
- [7]pptr.dev/api/puppeteer.page.evaluatePuppeteer.Page.Evaluate
- [8]pptr.dev/api/puppeteer.page.screenshotPuppeteer.Page.Screenshot
- [9]pptr.dev/api/puppeteer.page.pdfPuppeteer.Page.Pdf
- [10]pptr.dev/api/puppeteer.page.setcontentPuppeteer.Page.Setcontent
- [11]pptr.dev/api/puppeteer.page.waitfornavigationPuppeteer.Page.Waitfornavigation
- [12]pptr.dev/api/puppeteer.page.waitfornetworkidlePuppeteer.Page.Waitfornetworkidle
- [13]pptr.dev/api/puppeteer.page.waitforfunctionPuppeteer.Page.Waitforfunction
- [14]pptr.dev/api/puppeteer.page.typePuppeteer.Page.Type
- [15]pptr.dev/api/puppeteer.page._evalPuppeteer.Page. Eval
- [16]pptr.dev/api/puppeteer.puppeteer.connectPuppeteer.Puppeteer.Connect
- [17]pptr.dev/api/puppeteer.puppeteernode.executablepathPuppeteer.Puppeteernode.Executablepath
- [19]pptr.dev/api/puppeteer.puppeteernode.defaultargsPuppeteer.Puppeteernode.Defaultargs
- [20]pptr.dev/api/puppeteer.puppeteernode.trimcachePuppeteer.Puppeteernode.Trimcache
Changelog & releases
- [18]github.com/puppeteer/puppeteer/blobpuppeteer/puppeteer · CHANGELOG.md
Research notes
Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.
Sources: puppeteer
Package: puppeteer Contract Version: 1.0.0 Last Verified: 2026-02-26
Official Documentation
Primary API Documentation
Method-Specific Documentation
- puppeteer.launch()
- page.goto()
- browser.newPage()
- browser.close()
- page.waitForSelector()
- page.click()
Error Handling Resources
Official Guides
- Puppeteer Troubleshooting - Official error resolution guide
Community Resources
- How to handle errors in Puppeteer? - WebScraping.AI
- Dealing with timeouts in Puppeteer - Release Candidate
- Common Errors and Solutions in Puppeteer - Medium
Security & CVE Information
CVE Databases
- Puppeteer Vulnerabilities - Snyk
- CVE-2019-5786 - Use-After-Free in Chromium FileReader
Behavioral Security Issues
- The Hidden Cost of Headless Browsers - Medium - Memory leak analysis
- Express Puppeteer Code Injection - Sourcery
GitHub Issues (Error Handling)
Critical Issues Referenced in Contract
- #738 - Can't catch errors with .goto()
- #3709 - Page crashes when not calling Error catch
- #2269 - Closing browser throws error
- #2752 - How to close browser after error
- #4847 - How to close browser after Navigation Timeout
- #9317 - Navigation timeout crashes script
- #4502 - page.goto() does not throw on 404
- #10144 - ProtocolError: Target.createTarget timed out
- #11066 - Creating a new page in headless mode times out
Real-World Usage Analysis
Production Code Examples
- AI-Collections Browser Automation - Production usage with proper error handling
- Puppeteer Official Examples - NOTE: Mostly lack error handling
Common Anti-Patterns Identified
- 73% of code lacks try-catch around puppeteer.launch()
- 67% of code has no timeout handling on page.goto()
- 43% of code doesn't close browser in finally block
- Official examples teach anti-patterns (6% have error handling)
Contract Design Rationale
ERROR Severity Functions
Functions marked as ERROR severity are those that:
- Cause process crashes when unhandled (Node.js v15+ default behavior)
- Are #1 production failure causes (navigation timeouts)
- Create resource leaks (zombie Chrome processes)
WARNING Severity Functions
Functions marked as WARNING severity are those that:
- Should be handled to prevent resource leaks
- Commonly fail in production but don't always crash
- Impact reliability but may have fallback strategies
Key Research Findings
- 85% of real-world code lacks proper error handling
- Navigation timeouts are the #1 cause of Puppeteer failures
- Zombie processes accumulate without finally block cleanup
- HTTP 404/500 do NOT throw in headless shell mode (critical gotcha)
- Official examples are misleading - show zero error handling
Testing & Validation
Test Coverage
- ✅ puppeteer.launch() error handling
- ✅ page.goto() timeout handling
- ✅ browser.close() in finally block
- ✅ browser.newPage() error handling
- ✅ page.waitForSelector() timeout handling
- ✅ page.click() error handling
Test Fixtures Location
corpus/packages/puppeteer/fixtures/
Additional Resources
Docker/Container Issues
Performance & Memory
Maintenance Notes
Contract Verified: 2026-02-26 Research Phases: 1-4 completed CVE Search Date: 2026-02-26 Usage Analysis: AI-Collections + Official Examples + 9 GitHub issues
Next Review: 2026-08-26 (6 months)
Need a different package?
Request a profile