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
- Pass the function reference, not its result: page.on('request', logRequest) not logRequest()
- Guard optional handlers: if (handler) page.on('console', handler)
- Default to a no-op: page.on('console', handler ?? (() => {}))
- 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
- Pass function references, never call results: page.on('request', log) not log()
- Default optional handlers: page.on('console', handler ?? (() => {}))
- Type-check handlers in shared helpers before wiring events
- Watch for undefined after renames — a missing import silently becomes undefined
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
- iteration ended before page.on handler completed executing
- unknown browser event: %q, must be %q
- browser.on promise rejected: %w
- dispatching locator event %q to %q: %w
- waiting for page %s event: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/eeb6e93b8485ec67.
Report an issue: GitHub.