grafana/k6 · error
waiting for navigation: %w
Error message
waiting for navigation: %w
What it means
Same handler as the URL variant, but emitted when opts.URL is empty: Frame.WaitForNavigation was waiting for ANY navigation and the wait ended in error (usually timeout, wrapped in k6ext.UserFriendlyError with opts.Timeout) before a NavigationEvent arrived. Without a pattern there is nothing to match, so the message carries only the friendly timeout.
Source
Thrown at internal/js/modules/k6/browser/common/frame.go:2186
return nil, nil //nolint:nilnil
}
return resp, nil
}
func (f *Frame) handleWaitForNavigationTimeoutErrorFn(opts *FrameWaitForNavigationOptions) func(err error) error {
return func(err error) error {
f.log.Debugf("Frame:WaitForNavigation",
"fid:%v furl:%s timeoutCtx done: %v", f.ID(), f.URL(), err)
if err != nil {
e := &k6ext.UserFriendlyError{
Err: err,
Timeout: opts.Timeout,
}
if opts.URL != "" {
return fmt.Errorf("waiting for navigation to URL matching %q: %w", opts.URL, e)
}
return fmt.Errorf("waiting for navigation: %w", e)
}
return nil
}
}
// WaitForSelector waits for the given selector to match the waiting criteria.
func (f *Frame) WaitForSelector(selector string, popts *FrameWaitForSelectorOptions) (*ElementHandle, error) {
handle, err := f.waitForSelectorRetry(selector, popts, maxRetry)
if err != nil {
return nil, fmt.Errorf("waiting for selector %q: %w", selector, err)
}
return handle, nil
}
// WaitForTimeout waits the specified amount of milliseconds.
func (f *Frame) WaitForTimeout(timeout int64) {View on GitHub (pinned to 93accf6570)
Solutions
- Register the wait before the action and await both: const nav = page.waitForNavigation(); await el.click(); await nav;
- If it is an SPA route change, use page.waitForURL instead — a history pushState may not emit a navigation event
- Increase the timeout option
Example fix
// before
await page.click('#next');
await page.waitForNavigation(); // registered too late, or SPA route change emits nothing
// after
const nav = page.waitForNavigation({ timeout: 60_000 });
await page.click('#next');
await nav; Defensive patterns
Strategy: try-catch
Type guard
function isNavTimeoutNoURL(e) {
return e instanceof Error && /waiting for navigation/.test(e.message);
} Try / catch
try {
const nav = page.waitForNavigation({ timeout: 60_000 });
await el.click();
await nav;
} catch (e) {
if (isNavTimeoutNoURL(e)) { await page.waitForURL('**/next**'); } // SPA fallback
else throw e;
} Prevention
- For SPA history routing use waitForURL, not waitForNavigation
- Register the wait before the triggering action
When it happens
Trigger: page.waitForNavigation() with no url option where the accompanying action never triggers a navigation; the navigation occurs but the frame is detached or the page closes first; timeout too short for the new document's lifecycle.
Common situations: Clicking a button that only changes route via SPA history (no document navigation event in some setups); calling waitForNavigation after the navigation already happened; page.close() during the wait.
Related errors
- waiting for navigation to URL matching %q: %w
- browser.on promise rejected: %w
- %w: %w
- finding iframe with selector %q: %w
- clicking on element: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/6c79cb59d9278f07.
Report an issue: GitHub.