grafana/k6 · error
predicate function failed: %w
Error message
predicate function failed: %w
What it means
Thrown inside BrowserContext.runWaitForEventHandler when the user-supplied predicate passed to waitForEvent returns an error. The predicate is invoked with each new *Page; if it errors, the error is wrapped as 'predicate function failed' and delivered through waitForEvent's error channel, so it surfaces as a rejection of the waitForEvent call.
Source
Thrown at internal/js/modules/k6/browser/common/browser_context.go:433
continue
}
b.logger.Debugf("BrowserContext:runWaitForEventHandler:go():EventBrowserContextPage", "bctxid:%v", b.id)
p, ok := ev.data.(*Page)
if !ok {
errOut <- fmt.Errorf("on create page event failed to return a page: %w", k6error.ErrFatal)
return
}
if predicateFn == nil {
b.logger.Debugf("BrowserContext:runWaitForEventHandler:go():EventBrowserContextPage:return", "bctxid:%v", b.id)
out <- p
return
}
retVal, err := predicateFn(p)
if err != nil {
errOut <- fmt.Errorf("predicate function failed: %w", err)
return
}
if retVal {
b.logger.Debugf(
"BrowserContext:runWaitForEventHandler:go():EventBrowserContextPage:predicateFn:return",
"bctxid:%v", b.id,
)
out <- p
return
}
}
}
}
func (b *BrowserContext) getSession(id target.SessionID) *Session {
return b.browser.conn.getSession(id)
}View on GitHub (pinned to 93accf6570)
Solutions
- Inspect the wrapped error to find which operation inside the predicate failed and guard it.
- Make the predicate defensive: wrap page interactions in try/catch and return false on transient failures so the wait continues instead of failing.
- Only use cheap, synchronous checks in the predicate (match on URL/title) and do heavy work after waitForEvent resolves on the returned page.
- If the predicate must await something, return a promise that resolves to true/false rather than throwing.
Example fix
// before
const p = await ctx.waitForEvent('page', (page) => {
return page.url().includes('/dashboard'); // may throw if not ready
});
// after
const p = await ctx.waitForEvent('page', (page) => {
try {
return page.url().includes('/dashboard');
} catch {
return false; // keep waiting instead of failing
}
}); Defensive patterns
Strategy: try-catch
Try / catch
try {
const page = await context.waitForEvent('page', (p) => {
try {
return p.url().includes('/orders');
} catch {
return false; // transiently not ready: keep waiting
}
});
} catch (e) {
if (e.message.includes('predicate function failed')) {
// inspect the wrapped error: the predicate body itself threw
}
} Prevention
- Keep predicates synchronous and cheap (match on url/title), doing heavy work after the wait resolves.
- Wrap any page interaction inside the predicate in try/catch and return false instead of throwing.
- Avoid asserting final-state conditions in the predicate; new pages may still be on about:blank.
When it happens
Trigger: Calling browserContext.waitForEvent('page', (page) => { ... }) where the predicate body throws: calling a page API that fails (page.url(), page.title(), page.goto(...)), reading a property of an unexpectedly null object, or explicitly raising on a non-matching page.
Common situations: Predicates that immediately interact with the new page before it is ready (navigation not finished, frame not attached); predicates asserting on page.url() while the page is still on about:blank; predicates that call async APIs without awaiting them, producing unhandled rejections.
Related errors
- incorrect event %q, %q is the only event supported
- waitForEvent timed out after %v
- on create page event failed to return a page: %w
- iteration ended before page.on handler completed executing
- context is done before all '%s' events were processed
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/cffc0e85aa13fec5.
Report an issue: GitHub.