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

  1. Retry browser.newPage() once — this state is almost always transient
  2. If it recurs, recreate the whole browser (close and relaunch) inside the retry path rather than reusing the dead one
  3. Check container/host for OOM kills (dmesg, docker events) starving Chrome
  4. 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

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


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/ef7d68107ba04bd1. Report an issue: GitHub.