projectdiscovery/katana · warning

ErrNoNavigationPossible

ErrNoNavigationPossible

Error message

no navigation possible

What it means

ErrNoNavigationPossible is returned by navigateBackToStateOrigin when the crawler cannot restore the browser back to a previous state's origin page hash (newPageHash == ""). Crawl's loop catches it, logs at debug level, counts a consecutive failure and skips the action, so a crawl continues but that branch of exploration is abandoned.

Source

Thrown at pkg/engine/headless/crawler/state.go:118

	return state, nil
}

func sha256Hash(item string) string {
	hasher := sha256.New()
	hasher.Write([]byte(item))
	hashItem := hex.EncodeToString(hasher.Sum(nil))
	return hashItem
}

func getStrippedDOM(contents string) (string, error) {
	normalized, err := domNormalizer.Apply(contents)
	if err != nil {
		return "", errors.Wrap(err, "could not normalize dom")
	}
	return normalized, nil
}

var ErrNoNavigationPossible = errors.New("no navigation possible")

// navigateBackToStateOrigin implements the logic to navigate back to the state origin
//
// It implements different logics as an optimization to decide
// how to navigate back.
//
//  1. If the action has an element, check if the element is visible on the current page
//     If the element is visible, directly use that to navigate.
//
//  2. If we have browser history, and the page is in the history which was the origin
//     of the action, then we can directly use the browser history to navigate back.
//
// 3. If all else fails, we have the shortest path navigation.
func (c *Crawler) navigateBackToStateOrigin(action *types.Action, page *browser.BrowserPage, currentPageHash string) (string, error) {
	c.logger.Debug("Found action with different origin id",
		slog.String("action_origin_id", action.OriginID),
		slog.String("current_page_hash", currentPageHash),
	)

View on GitHub (pinned to e3e742739c)

Solutions

  1. Treat as skippable — the crawler already increments consecutiveFailures and moves on
  2. Reduce actions that open new windows (browser popup blocking options)
  3. Increase per-page wait/retry so navigation-back strategies have time to succeed
  4. Check debug logs (logger.Debug) to identify which actions cause it

Example fix

// before: aborting crawl on this error
if err := c.Crawl(ctx); err != nil { log.Fatal(err) }
// after
if err := c.Crawl(ctx); err != nil && !errors.Is(err, crawler.ErrNoNavigationPossible) { log.Fatal(err) }
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure history is navigable before relying on back-navigation:
if len(page.History()) < 2 { skip back-navigation strategy }

Type guard

func isNoNavigationPossible(err error) bool { return errors.Is(err, crawler.ErrNoNavigationPossible) }

Try / catch

if errors.Is(err, crawler.ErrNoNavigationPossible) {
    log.Debug("skipping action: no navigation possible")
    consecutiveFailures++
    continue
}

Prevention

When it happens

Trigger: After executing an action, the crawler tries to navigate back to the state origin (history back, re-navigation heuristics) and every strategy yields an empty page hash (state.go:171) — e.g. the action opened a new tab, destroyed history, or landed on about:blank.

Common situations: Actions that spawn popups or replace the document such that 'back' is impossible; sites that rewrite history (pushState loops); sessions expiring mid-crawl so replaying navigation fails.

Related errors


AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03). Data as JSON: /api/errors/be12b052e9ffab2b. Report an issue: GitHub.