grafana/k6 · error · TypeError

The "listener" argument must be a function

Error message

The "listener" argument must be a function

What it means

The browser module maps page.on(event, handler) onto typed internal handlers; before dispatching it checks that the second argument is a sobek.Callable. Passing anything that is not a function — undefined, null, an object, or the result of calling a function — raises this TypeError, mirroring Node's EventEmitter behavior.

Source

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

			}
			var mehs []mapping
			for _, eh := range ehs {
				ehm := mapElementHandle(vu, eh)
				mehs = append(mehs, ehm)
			}
			return mehs, nil
		})
	}

	return maps
}

// mapPageOn enables using various page.on event handlers with the page.on method.
// It provides a generic way to map different event types to their respective handler functions.
func mapPageOn(vu moduleVU, p *common.Page) func(common.PageEventName, sobek.Callable) error {
	return func(eventName common.PageEventName, handle sobek.Callable) error {
		if handle == nil {
			panic(vu.Runtime().NewTypeError(`The "listener" argument must be a function`))
		}

		pageEvents := map[common.PageEventName]struct {
			mapp func(vu moduleVU, event common.PageEvent) mapping
			wait bool // Whether to wait for the handler to complete.
		}{
			common.PageEventConsole:         {mapp: mapConsoleMessage},
			common.PageEventMetric:          {mapp: mapMetricEvent, wait: true},
			common.PageEventRequest:         {mapp: mapRequestEvent},
			common.PageEventResponse:        {mapp: mapResponseEvent},
			common.PageEventRequestFinished: {mapp: mapRequestEvent},
			common.PageEventRequestFailed:   {mapp: mapRequestEvent},
		}
		pageEvent, ok := pageEvents[eventName]
		if !ok {
			return fmt.Errorf("unknown page on event: %q", eventName)
		}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Pass the function reference, not its result: page.on('request', logRequest) not logRequest()
  2. Guard optional handlers: if (handler) page.on('console', handler)
  3. Default to a no-op: page.on('console', handler ?? (() => {}))
  4. Check typeof handler === 'function' at the call site in shared test-framework code

Example fix

// before
page.on('console', logger.log()); // invokes now, passes undefined

// after
page.on('console', logger.log); // reference only
// optional handler:
page.on('console', maybeHandler ?? (() => {}));
Defensive patterns

Strategy: type-guard

Validate before calling

function onPage(page, event, handler) {
  if (typeof handler !== 'function') throw new TypeError(`page.on('${event}') needs a function, got ${typeof handler}`);
  return page.on(event, handler);
}

Type guard

const isCallable = v => typeof v === 'function';
const safeHandler = (fn, fallback = () => {}) => isCallable(fn) ? fn : fallback;

Try / catch

try { page.on(event, handler); } catch (e) { if (/listener.*function/.test(e.message)) throw new TypeError(`handler for '${event}' missing or not a function`); throw e; }

Prevention

When it happens

Trigger: page.on('console', undefined) when a handler variable is missing; page.on('request', logRequest()) calling instead of referencing (returns undefined); page.on('response', { handle: fn }) passing an object with a method; forgetting the second argument entirely while testing. Applies to all page events: console, metric handled wait-style, request, response, requestFinished, requestFailed, etc.

Common situations: Optional handlers wired from config (handler only defined for some events); refactors renaming functions and leaving stale references that evaluate to undefined; copy-paste from browser docs into a k6 script where a helper wasn't ported; arrow-function typos like page.on('close', () => {}) written as page.on('close', () => {})) with a stray call.

Related errors


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