grafana/k6 · error

evaluateHandle requires a page function

Error message

evaluateHandle requires a page function

What it means

frame.evaluateHandle(pageFunc, ...args) was called with a nullish, empty, or whitespace-only page function (frame_mapping.go:83, same sobekEmptyString check as evaluate). Unlike evaluate, evaluateHandle returns a JSHandle to an in-page object, but the input validation is identical: the serialized function string must be non-empty.

Source

Thrown at internal/js/modules/k6/browser/browser/frame_mapping.go:83

			}
			earg := exportArg(eventInit)
			return promise(vu, func() (any, error) {
				return nil, f.DispatchEvent(selector, typ, earg, popts) //nolint:wrapcheck
			}), nil
		},
		"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 f.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 := f.EvaluateHandle(funcString, gopts...)
				if err != nil {
					return nil, err //nolint:wrapcheck
				}
				return mapJSHandle(vu, jsh), nil
			}), nil
		},
		"fill": func(selector, value string, opts sobek.Value) (*sobek.Promise, error) {
			popts := common.NewFrameFillOptions(f.Timeout())
			if err := popts.Parse(vu.Context(), opts); err != nil {
				return nil, fmt.Errorf("parsing fill options: %w", err)
			}
			return promise(vu, func() (any, error) {
				return nil, f.Fill(selector, value, popts) //nolint:wrapcheck

View on GitHub (pinned to 93accf6570)

Solutions

  1. Pass a concrete function: frame.evaluateHandle(() => document.body) or non-empty string
  2. Validate the source before calling: if (typeof fn !== 'function' && !String(fn).trim()) fail fast with a clear message
  3. Log the value being passed when this error appears - it is almost always undefined or ''

Example fix

// before
let factory;
frame.evaluateHandle(factory);
// after
const factory = () => document.createElement('div');
frame.evaluateHandle(factory);
Defensive patterns

Strategy: type-guard

Validate before calling

const fn = typeof pageFunc === 'function' ? pageFunc.toString()
          : typeof pageFunc === 'string' ? pageFunc.trim() : '';
if (!fn) throw new Error('frame.evaluateHandle needs a non-empty function or string');

Type guard

function isUsablePageFunction(v) {
  if (v == null) return false;
  if (typeof v === 'function') return true;
  return typeof v === 'string' && v.trim().length > 0;
}

Try / catch

try {
  const h = await frame.evaluateHandle(fn, ...args);
} catch (e) {
  console.error(`evaluateHandle failed: ${e.message}`);
}

Prevention

When it happens

Trigger: frame.evaluateHandle(undefined), frame.evaluateHandle(''), or a whitespace-only string/function variable; error is thrown synchronously before the promise is created.

Common situations: Same as 429: empty template strings, unset variables, helper functions returning undefined; also code paths that branch between evaluate and evaluateHandle and forward a possibly-empty expression.

Related errors


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