grafana/k6 · error
navigating to history entry
Error message
navigating %s to history entry %d: %w
What it means
This error is returned by Page.GoBack/GoForward (page.go history navigation) when the CDP call Page.navigate_to_history_entry fails while moving the page to a target index in the session history. The '%s' is the target URL taken from the history entries list and '%d' the history entry ID; failure usually means the browser target was closed, the navigation was interrupted, or the underlying CDP session dropped. A separate timeout wrapper converts deadline overruns into a k6ext.UserFriendlyError, so this specific wrap is for non-timeout protocol failures.
Solutions
- Verify the browser tab/target is still open before calling goBack/goForward
- Retry the navigation after waiting for the page to reach a stable lifecycle state
- Increase the navigation timeout option if the failure is caused by an overruns of the per-call deadline
- Check that no other code (e.g. page.close()) races with the history navigation
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at internal/js/modules/k6/browser/common/page.go:1659 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/5b7dd38c3d2dfdd7.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/page.go:1664
targetURL := entries[targetIndex].URL
timeoutCtx, timeoutCancelFn := context.WithTimeout(p.ctx, opts.Timeout)
defer timeoutCancelFn()
navAction := page.NavigateToHistoryEntry(historyEntryID)
if err := navAction.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {
return nil, fmt.Errorf("navigating to history entry %d: %w", historyEntryID, err)
}
wrapTimeoutError := func(err error) error {
if errors.Is(err, context.DeadlineExceeded) {
err = &k6ext.UserFriendlyError{
Err: err,
Timeout: opts.Timeout,
}
}
p.logger.Debugf("Page:GoBackForward", "timeoutCtx done: %v", err)
return fmt.Errorf("navigating %s to history entry %d: %w", direction, historyEntryID, err)
}
// Poll for URL change, don't rely on lifecycle events since bfcache
// restorations don't re-fire them.
ticker := time.NewTicker(50 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-p.ctx.Done():
return nil, ContextErr(p.ctx)
case <-timeoutCtx.Done():
return nil, wrapTimeoutError(ContextErr(timeoutCtx))
case <-ticker.C:
mainFrame := p.frameManager.MainFrame()
if mainFrame == nil {
continue
}View on GitHub (pinned to 3fcf5388d7)