grafana/k6 · error

evaluate requires a page function

Error message

evaluate requires a page function

What it means

Thrown synchronously by page.evaluate(pageFunc, ...args) when the first argument is nullish, empty, or whitespace-only. The guard sobekEmptyString (internal/js/modules/k6/browser/browser/helpers.go:66-68) treats undefined, null and any string that trims to empty as missing. The check happens before the promise is created, so the call throws immediately and no browser code runs.

Solutions

  1. Pass a function: page.evaluate(() => document.title)
  2. If the function comes from a variable, verify it before the call: if (!fn || (typeof fn === 'string' && !fn.trim())) throw new Error('...')
  3. Check for typos or missing imports on the variable you are passing

Example fix

// before
const fn = handlers[mode];        // undefined when mode is unknown
await page.evaluate(fn);
// evaluate requires a page function

// after
const fn = handlers[mode];
if (!fn) throw new Error(`no handler for mode ${mode}`);
await page.evaluate(fn);
Defensive patterns

Strategy: validation

Validate before calling

function requirePageFunc(fn) {
  if (fn === undefined || fn === null) throw new Error('page function is required');
  if (typeof fn === 'string' && fn.trim() === '') throw new Error('page function string is empty');
  if (typeof fn !== 'function' && typeof fn !== 'string') throw new Error('page function must be a function or string');
  return fn;
}
await page.evaluate(requirePageFunc(userFunc), ...args);

Type guard

/** @param {unknown} fn */
function isPageFunc(fn) {
  if (typeof fn === 'function') return true;
  return typeof fn === 'string' && fn.trim().length > 0;
}

Try / catch

try {
  await page.evaluate(userFunc, ...args);
} catch (e) {
  if (String(e).includes('evaluate requires a page function')) {
    console.warn(`evaluate called with missing function (${name}); skipping`);
  } else throw e;
}

Prevention

When it happens

Trigger: page.evaluate('') or page.evaluate(' '); page.evaluate(null) / page.evaluate(undefined); passing a variable that was never assigned or an optional-chaining result; template literals that render empty, e.g. page.evaluate(``); calling page.evaluate() with no arguments at all.

Common situations: Selecting a function at runtime (desktop vs mobile handler) and picking an undefined branch; passing a function name that is misspelled so JS yields undefined; building the page function from empty config strings.

Related errors


AI-assisted analysis of grafana/k6@8d06114777 (2026-08-18). Data as JSON: /api/errors/44ef49d48fe93b94. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/browser/page_mapping.go:107

			}), nil
		},
		"emulateMedia": func(opts sobek.Value) (*sobek.Promise, error) {
			popts, err := parsePageEmulateMediaOptions(rt, opts, common.NewPageEmulateMediaOptions(p))
			if err != nil {
				return nil, fmt.Errorf("parsing emulateMedia options: %w", err)
			}
			return promise(vu, func() (any, error) {
				return nil, p.EmulateMedia(popts) //nolint:wrapcheck
			}), nil
		},
		"emulateVisionDeficiency": func(typ string) *sobek.Promise {
			return promise(vu, func() (any, error) {
				return nil, p.EmulateVisionDeficiency(typ) //nolint:wrapcheck
			})
		},
		"evaluate": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {
			if sobekEmptyString(pageFunc) {
				return nil, fmt.Errorf("evaluate requires a page function")
			}
			funcString := pageFunc.String()
			gopts := exportArgs(gargs)
			return promise(vu, func() (any, error) {
				return p.Evaluate(funcString, gopts...)
			}), nil
		},
		"evaluateHandle": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {
			if sobekEmptyString(pageFunc) {
				return nil, fmt.Errorf("evaluateHandle requires a page function")
			}
			funcString := pageFunc.String()
			gopts := exportArgs(gargs)
			return promise(vu, func() (any, error) {
				jsh, err := p.EvaluateHandle(funcString, gopts...)
				if err != nil {
					return nil, err //nolint:wrapcheck
				}

View on GitHub (pinned to 8d06114777)