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
Browser.newPageInContext treats 'no page AND no error' after Target.createTarget as an impossible outcome and converts it into a wrapped UserFriendlyError with this message (internal/js/modules/k6/browser/common/browser.go:564). It fires when the CDP call neither failed nor produced a usable page before the context finished — typically the target was destroyed immediately, the browser died, or a timeout raced page creation.
Solutions
- Retry the page creation once with a short backoff — this is frequently a transient race
- Raise the browser timeout: K6_BROWSER_TIMEOUT=60s (or the timeout browser option)
- Check the remote browser's health and logs (container restarts, OOM kills) and give it more memory/CPU
- Ensure nothing closes the browser/context concurrently with newPage()
- Upgrade k6 — page-creation and timeout paths have been hardened across releases
Example fix
// before
const page = await browser.newPage();
// after
async function newPageWithRetry(browser, tries = 2) {
for (let i = 0; ; i++) {
try { return await browser.newPage(); }
catch (e) {
if (i >= tries || !/unknown reason/.test(e.message)) throw e;
await new Promise((r) => setTimeout(r, 500));
}
}
}
const page = await newPageWithRetry(browser); Defensive patterns
Strategy: retry
Validate before calling
// cheap pre-flight for a remote browser before creating pages
import http from 'k6/http';
const checkBrowserUp = (endpoint) => http.get(`http://${endpoint}/json/version`).status === 200; Try / catch
async function newPageWithRetry(browser, tries = 2, delayMs = 500) {
for (let i = 0; ; i++) {
try {
return await browser.newPage();
} catch (e) {
if (i >= tries || !/unknown reason/.test(String(e?.message || e))) throw e;
await new Promise((r) => setTimeout(r, delayMs));
}
}
} Prevention
- Set a generous browser timeout (K6_BROWSER_TIMEOUT or the timeout option) instead of defaults under load
- Healthcheck remote browsers (/json/version) before the run and watch for container OOM restarts
- Serialize page creation; avoid launching many pages concurrently against one browser
- Keep k6 current — page-creation and timeout handling improve release over release
When it happens
Trigger: browser.newPage() racing browser/context close; a remote wsURL browser crashing or being OOM-killed mid-call; a low browser timeout (K6_BROWSER_TIMEOUT / timeout option) expiring exactly during page creation; Chromium killing the target on startup (bad flags, corrupt data dir).
Common situations: Containerized/remote Chrome under memory pressure restarting between calls; scenarios launching many pages concurrently; flaky CI where the browser container is still starting; leftover chrome processes locking the user-data dir.
Related errors
- creating a new blank page
- creating a new
- getting iframe frame
- WebSocket endpoint cannot be empty
- adding init script to browser context
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/ef7d68107ba04bd1.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/browser.go:559
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 3fcf5388d7)