grafana/k6 · error

predicate function is not callable

Error message

predicate function is not callable

What it means

browserContext.waitForEvent accepts either a bare predicate function or an options object; in the object form the `predicate` member must itself be callable. parseWaitForEventOptions uses sobek.AssertFunction, which fails for numbers, strings, undefined, or non-function values (browser_context_mapping.go:215).

Source

Thrown at internal/js/modules/k6/browser/browser/browser_context_mapping.go:215

		Timeout: defaultTime,
	}

	if k6common.IsNullish(optsOrPredicate) {
		return w, nil
	}
	var isCallable bool
	w.PredicateFn, isCallable = sobek.AssertFunction(optsOrPredicate)
	if isCallable {
		return w, nil
	}

	opts := optsOrPredicate.ToObject(rt)
	for _, k := range opts.Keys() {
		switch k {
		case "predicate":
			w.PredicateFn, isCallable = sobek.AssertFunction(opts.Get(k))
			if !isCallable {
				return nil, errors.New("predicate function is not callable")
			}
		case "timeout":
			w.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond
		default:
			return nil, fmt.Errorf("unknown option: %s", k)
		}
	}

	return w, nil
}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Pass the function reference, not its result: `{ predicate: (page) => page.url().includes('x') }`
  2. Or pass the predicate directly as the second arg: `waitForEvent('page', (page) => ...)`
  3. Keep `timeout` (ms, number) as the only other key in the object form

Example fix

// before
const page = await context.waitForEvent('page', { predicate: isTargetPage() });

// after
const page = await context.waitForEvent('page', { predicate: isTargetPage });
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate the options object before calling waitForEvent
function isWaitForEventOpts(v) {
  if (typeof v === 'function') return true;
  if (v === null || typeof v !== 'object') return false;
  const keys = Object.keys(v);
  return keys.every((k) => k === 'predicate' || k === 'timeout') &&
    (v.predicate === undefined || typeof v.predicate === 'function') &&
    (v.timeout === undefined || typeof v.timeout === 'number');
}

Type guard

const isPredicateCallable = (o) => o == null || typeof o === 'function' || typeof o.predicate === 'function';

Try / catch

try {
  const page = await context.waitForEvent('page', { predicate: isTargetPage, timeout: 30_000 });
} catch (e) {
  if (/predicate function is not callable/.test(e.message)) throw new TypeError('waitForEvent: pass the function reference, not its return value');
  throw e;
}

Prevention

When it happens

Trigger: `context.waitForEvent('page', { predicate: fn() })` — invoking the function and passing its return value; `{ predicate: 'selector' }`; `{ predicate: undefined }`; also any unknown key in the object form yields the sibling 'unknown option' error.

Common situations: Copy-pasting Playwright examples where strings are accepted; accidentally executing the predicate while wiring it; refactoring the predicate into a value.

Related errors


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