{"record":{"id":"138da84a6d3d9878","repo":"projectdiscovery/katana","slug":"could-not-find-shortest-path","errorCode":null,"errorMessage":"could not find shortest path","messagePattern":"could not find shortest path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/engine/headless/graph/graph.go","lineNumber":116,"sourceCode":"\t\t\treturn nil\n\t\t}\n\t\treturn errors.Wrap(err, \"could not add edge to graph\")\n\t}\n\treturn nil\n}\n\nfunc (g *CrawlGraph) GetPageState(id string) (*types.PageState, error) {\n\tpageVertex, err := g.graph.Vertex(id)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"could not get vertex\")\n\t}\n\treturn &pageVertex, nil\n}\n\nfunc (g *CrawlGraph) ShortestPath(sourceState, targetState string) ([]*types.Action, error) {\n\tshortestPath, err := graph.ShortestPath(g.graph, sourceState, targetState)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"could not find shortest path\")\n\t}\n\tactionsSlice := make([]*types.Action, 0, len(shortestPath))\n\tfor _, path := range shortestPath {\n\t\tpageVertex, err := g.graph.Vertex(path)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"could not get vertex\")\n\t\t}\n\n\t\tif pageVertex.URL == \"about:blank\" || pageVertex.NavigationAction == nil {\n\t\t\tcontinue\n\t\t}\n\t\tactionsSlice = append(actionsSlice, pageVertex.NavigationAction)\n\t}\n\treturn actionsSlice, nil\n}\n\nfunc (g *CrawlGraph) DrawGraph(file string) error {\n\tf, err := os.Create(file)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/projectdiscovery/katana/blob/e3e742739c3746f085943ce918fb4e2b8daf6fe6/pkg/engine/headless/graph/graph.go#L98-L134","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","solutions":["Check that the target state exists in the graph (g.graph.Vertex(targetState) succeeds) before calling ShortestPath.","Verify the crawl actually visited the target URL; widen crawl scope/depth or navigate the target manually so it is added to the graph.","Rebuild the graph by re-running the crawl if using a stale or persisted graph whose vertex IDs no longer match.","Handle the error as a control-flow signal: fall back to a direct navigation to the target URL instead of replaying a path."],"exampleFix":"// before\nactions, err := graph.ShortestPath(currentState, targetState)\n// after\nif _, err := graph.Graph().Vertex(targetState); err != nil {\n    return page.Navigate(targetURL) // target not in graph; navigate directly\n}\nactions, err := graph.ShortestPath(currentState, targetState)","handlingStrategy":"fallback","validationCode":"// ensure both vertices exist before pathfinding\nif _, err := graph.Graph().Vertex(sourceState); err != nil {\n    return fmt.Errorf(\"source state %q not in graph\", sourceState)\n}\nif _, err := graph.Graph().Vertex(targetState); err != nil {\n    return fmt.Errorf(\"target state %q not in graph\", targetState)\n}","typeGuard":null,"tryCatchPattern":"// Go: check error and fall back to direct navigation\nactions, err := crawlGraph.ShortestPath(src, dst)\nif err != nil {\n    var target *errors.Error\n    if stdErrors.As(err, &target) && strings.Contains(err.Error(), \"could not find shortest path\") {\n        return page.Navigate(targetURL) // fallback\n    }\n    return err\n}","preventionTips":["Confirm the crawl visited the target URL before requesting a path to it.","Validate source/target vertex IDs against the current graph instance, not a stale one.","Fall back to direct navigation when no path exists instead of failing the run."],"tags":["graph","navigation","crawl-engine"],"backgroundTag":"no-path-in-graph","analyzedSha":"e3e742739c3746f085943ce918fb4e2b8daf6fe6","analyzedAt":"2026-09-03T14:55:13.248Z","contentChangedAt":"2026-09-03T14:55:13.248Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}