projectdiscovery/katana · error

could not find shortest path

Error message

could not find shortest path

What it means

CrawlGraph.ShortestPath wraps a failure from the underlying gonum graph.ShortestPath call when computing the shortest action path between two crawl states. It means no path could be computed from sourceState to targetState — most often the target (or source) vertex does not exist in the graph, or the vertices are not connected. This is an expected domain outcome during crawling when a page was never reached or was pruned.

Source

Thrown at pkg/engine/headless/graph/graph.go:116

			return nil
		}
		return errors.Wrap(err, "could not add edge to graph")
	}
	return nil
}

func (g *CrawlGraph) GetPageState(id string) (*types.PageState, error) {
	pageVertex, err := g.graph.Vertex(id)
	if err != nil {
		return nil, errors.Wrap(err, "could not get vertex")
	}
	return &pageVertex, nil
}

func (g *CrawlGraph) ShortestPath(sourceState, targetState string) ([]*types.Action, error) {
	shortestPath, err := graph.ShortestPath(g.graph, sourceState, targetState)
	if err != nil {
		return nil, errors.Wrap(err, "could not find shortest path")
	}
	actionsSlice := make([]*types.Action, 0, len(shortestPath))
	for _, path := range shortestPath {
		pageVertex, err := g.graph.Vertex(path)
		if err != nil {
			return nil, errors.Wrap(err, "could not get vertex")
		}

		if pageVertex.URL == "about:blank" || pageVertex.NavigationAction == nil {
			continue
		}
		actionsSlice = append(actionsSlice, pageVertex.NavigationAction)
	}
	return actionsSlice, nil
}

func (g *CrawlGraph) DrawGraph(file string) error {
	f, err := os.Create(file)

View on GitHub (pinned to e3e742739c)

Solutions

  1. Check that the target state exists in the graph (g.graph.Vertex(targetState) succeeds) before calling ShortestPath.
  2. Verify the crawl actually visited the target URL; widen crawl scope/depth or navigate the target manually so it is added to the graph.
  3. Rebuild the graph by re-running the crawl if using a stale or persisted graph whose vertex IDs no longer match.
  4. Handle the error as a control-flow signal: fall back to a direct navigation to the target URL instead of replaying a path.

Example fix

// before
actions, err := graph.ShortestPath(currentState, targetState)
// after
if _, err := graph.Graph().Vertex(targetState); err != nil {
    return page.Navigate(targetURL) // target not in graph; navigate directly
}
actions, err := graph.ShortestPath(currentState, targetState)
Defensive patterns

Strategy: fallback

Validate before calling

// ensure both vertices exist before pathfinding
if _, err := graph.Graph().Vertex(sourceState); err != nil {
    return fmt.Errorf("source state %q not in graph", sourceState)
}
if _, err := graph.Graph().Vertex(targetState); err != nil {
    return fmt.Errorf("target state %q not in graph", targetState)
}

Try / catch

// Go: check error and fall back to direct navigation
actions, err := crawlGraph.ShortestPath(src, dst)
if err != nil {
    var target *errors.Error
    if stdErrors.As(err, &target) && strings.Contains(err.Error(), "could not find shortest path") {
        return page.Navigate(targetURL) // fallback
    }
    return err
}

Prevention

When it happens

Trigger: Calling ShortestPath(source, target) when the target state was never crawled into the graph, when the source/target vertex ID is misspelled or stale (graph from an earlier run), or when no sequence of actions connects the two states (disconnected crawl graph).

Common situations: Attempting to navigate to a URL/state the crawler skipped due to scope filters or depth limits; reusing a saved graph from a previous run whose vertex IDs changed; requesting a path between pages that live in different components of the crawl (e.g. after login segmentation).

Related errors


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