grafana/k6 · error

waiting for function, polling: %w

Error message

waiting for function, polling: %w

What it means

Thrown by Frame.WaitForFunction when the injected polling script (the helper that repeatedly calls your predicate inside the page) cannot be evaluated or the predicate's evaluation chain fails. The %w wraps the underlying CDP Runtime.evaluate error, so the real cause (JS exception in the predicate, destroyed execution context, or timeout) is in the wrapped message. This is k6's browser module translating a failed in-page polling loop into a Go error.

Source

Thrown at internal/js/modules/k6/browser/common/frame.go:2018

	// First evaluate the predicate function itself to get its handle.
	opts := evalOptions{forceCallable: false, returnByValue: false}
	handle, err := execCtx.eval(apiCtx, opts, js)
	if err != nil {
		return nil, fmt.Errorf("waiting for function, getting handle: %w", err)
	}

	// Then evaluate the injected function call, passing it the predicate
	// function handle and the rest of the arguments.
	opts = evalOptions{forceCallable: true, returnByValue: false}
	result, err := execCtx.eval(
		apiCtx, opts, pageFn, append([]any{
			injected,
			handle,
			polling,
			timeout.Milliseconds(), // The JS value is in ms integers
		}, args...)...)
	if err != nil {
		return nil, fmt.Errorf("waiting for function, polling: %w", err)
	}
	// prevent passing a non-nil interface to the upper layers.
	if result == nil {
		return nil, nil //nolint:nilnil
	}

	return result, nil
}

// WaitForLoadState waits for the given load state to be reached.
// This will unblock if that lifecycle event has already been received.
func (f *Frame) WaitForLoadState(state string, popts *FrameWaitForLoadStateOptions) error {
	f.log.Debugf("Frame:WaitForLoadState", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)
	defer f.log.Debugf("Frame:WaitForLoadState:return", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)

	timeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, popts.Timeout)
	defer timeoutCancel()

View on GitHub (pinned to 93accf6570)

Solutions

  1. Wrap the predicate body in try/catch and return false on internal errors so a transient JS error does not abort polling
  2. Make sure a navigation is not in progress: await page.goto(...) or page.waitForLoadState() before waitForFunction
  3. Increase the timeout option (default 30s) to cover slow pages
  4. Read the wrapped (%w) error text: 'context destroyed' points to navigation races, a JS stack points to your predicate

Example fix

// before
page.waitForFunction(() => window.results.length > 0);

// after
page.waitForFunction(
  () => { try { return window.results.length > 0; } catch { return false; } },
  { timeout: 60_000, polling: 500 }
);
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof page.waitForFunction !== 'function') throw new Error('page is closed or invalid');

Type guard

function isWaitForFunctionTimeout(e) {
  return e instanceof Error && /waiting for function, polling/.test(e.message);
}

Try / catch

try {
  await page.waitForFunction(() => window.ready === true, { timeout: 60_000, polling: 500 });
} catch (e) {
  if (isWaitForFunctionTimeout(e)) { /* re-check condition once, then fail with context */ }
  throw e;
}

Prevention

When it happens

Trigger: Calling page.waitForFunction(fn, arg, {polling: 'raf'|interval, timeout}) where fn throws a JavaScript exception on every poll; the frame navigates while polling is in flight (execution context destroyed); the timeout expires and the injected script rejects; passing a polling value the injected helper cannot use.

Common situations: A predicate that references a DOM node that disappears during the wait; calling waitForFunction immediately after page.goto while the document is still swapping contexts; very short timeouts on pages where the condition only becomes true late; k6 versions where context-destruction races during navigation surfaced here.

Related errors


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