grafana/k6 · error · UserFriendlyError
can't fetch the page for unknown reason
Error message
can't fetch the page for unknown reason
What it means
newPageInContext wraps CDP page creation and enforces an internal invariant: if the call returns neither an error nor a page, k6 wraps this generic UserFriendlyError ('can't fetch the page for unknown reason') instead of returning a nil page that would panic later. It typically indicates the browser died or the CDP connection dropped at exactly the wrong moment — or a k6 bug — since normal failures carry a real error.
Source
Thrown at internal/js/modules/k6/browser/common/browser.go:564
case <-waitForPage:
b.logger.Debugf("Browser:newPageInContext:<-waitForPage", "tid:%v bctxid:%v", tid, id)
b.pagesMu.RLock()
page = b.pages[tid]
b.pagesMu.RUnlock()
case <-ctx.Done():
b.logger.Debugf("Browser:newPageInContext:<-ctx.Done", "tid:%v bctxid:%v err:%v", tid, id, ContextErr(ctx))
}
if err = ContextErr(ctx); err != nil {
err = &k6ext.UserFriendlyError{
Err: err,
Timeout: b.browserOpts.Timeout,
}
}
if err == nil && page == nil {
err = &k6ext.UserFriendlyError{
Err: errors.New("can't fetch the page for unknown reason"),
}
}
return page, err
}
// Close shuts down the browser.
func (b *Browser) Close() {
if !b.closing.CompareAndSwap(false, true) {
b.logger.Warnf(
"Browser:Close",
"Please call browser.close only once, and do not use the browser after calling close.",
)
return
}
// This will help with some cleanup in the connection and event loop above in
// initEvents().
defer b.browserCancelFn(errors.New("browser closed"))View on GitHub (pinned to 93accf6570)
Solutions
- Retry browser.newPage() once — this state is almost always transient
- If it recurs, recreate the whole browser (close and relaunch) inside the retry path rather than reusing the dead one
- Check container/host for OOM kills (dmesg, docker events) starving Chrome
- Upgrade k6 and Chrome together; if it persists, capture --log-output=stdout and report it with the script
Example fix
// before
const page = await browser.newPage();
// after
async function newPageWithRetry(browser) {
try {
return await browser.newPage();
} catch (e) {
if (!e.message.includes("can't fetch the page")) throw e;
return await browser.newPage(); // one retry
}
}
const page = await newPageWithRetry(browser); Defensive patterns
Strategy: retry
Try / catch
async function safeNewPage(browser, attempts = 2) {
let lastErr;
for (let i = 0; i < attempts; i++) {
try {
return await browser.newPage();
} catch (e) {
lastErr = e;
if (!e.message.includes("can't fetch the page")) break;
}
}
throw lastErr;
} Prevention
- Create pages early in the iteration, not concurrently with teardown/close
- Give Chrome enough memory in containers so the process is not OOM-killed mid-call
- Keep k6 and the browser binary updated in lockstep; pin both in CI images
When it happens
Trigger: browser.newPage() racing browser.close() or the iteration teardown; the browser process being killed (OOM, docker stop, sandbox kills) while the page is being created; rare CDP/protocol anomalies between k6 and unusual Chrome builds.
Common situations: Flaky end-of-test page creation; container memory limits reaping Chrome; parallel VUs stressing a single browser; k6/Chrome version skew after an image upgrade.
Related errors
- removing frames recursively: detaching frame: %w
- adding k6 object to new browser context: %w
- querying selector %q, wrong type %T
- getting element handle for selector %q: %w
- unexpected select element type %T
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/ef7d68107ba04bd1.
Report an issue: GitHub.