{"record":{"id":"8602578d276263e9","repo":"a-b-street/abstreet","slug":"empty-path","errorCode":null,"errorMessage":"Empty path","messagePattern":"Empty path","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/pathfind/v1.rs","lineNumber":749,"sourceCode":"                map.get_l(req.end.lane()).get_directed_parent(),\n            );\n            let pair = common.entry(key).or_insert_with(|| (req, 0));\n            pair.1 += 1;\n        }\n        if false {\n            info!(\n                \"{} requests deduplicated down to {}\",\n                prettyprint_usize(count_before),\n                prettyprint_usize(common.len())\n            );\n        }\n        common.into_values().collect()\n    }\n}\n\nfn validate_continuity(map: &Map, steps: &[PathStep]) {\n    if steps.is_empty() {\n        panic!(\"Empty path\");\n    }\n    for pair in steps.windows(2) {\n        let from = match pair[0] {\n            PathStep::Lane(id) => map.get_l(id).last_pt(),\n            PathStep::ContraflowLane(id) => map.get_l(id).first_pt(),\n            PathStep::Turn(id) => map.get_t(id).geom.last_pt(),\n            PathStep::ContraflowTurn(id) => map.get_t(id).geom.first_pt(),\n        };\n        let to = match pair[1] {\n            PathStep::Lane(id) => map.get_l(id).first_pt(),\n            PathStep::ContraflowLane(id) => map.get_l(id).last_pt(),\n            PathStep::Turn(id) => map.get_t(id).geom.first_pt(),\n            PathStep::ContraflowTurn(id) => map.get_t(id).geom.last_pt(),\n        };\n        let len = from.dist_to(to);\n        if len > EPSILON_DIST {\n            println!(\"All steps in invalid path:\");\n            for s in steps {","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/pathfind/v1.rs#L731-L767","documentation":"This panic fires during path construction when the pathfinding engine produces a Path with zero steps. validate_continuity, run as an internal sanity check by Path::new, treats an empty step list as a broken result because a valid path must always contain at least one lane or turn step. It signals an internal pathfinding bug, not a caller mistake.","triggerScenarios":"Calling Path::new (directly or via any pathfind request) when the underlying algorithm returns an empty Vec<PathStep>, e.g. after map edits change the road graph or when start and end collapse into a degenerate position.","commonSituations":"Hit by developers editing maps in A/B Street's editor, regenerating map models from new OSM data, or upgrading to a map version where pathfind internals changed; never from normal user API misuse.","solutions":["Check whether start and end of the PathRequest are identical or effectively the same position and handle that case before calling pathfind","Update map_model / regenerate the map so the map version matches the pathfind code, since graph edits can desynchronize the algorithm","Report upstream with the PathRequest and map file; empty results indicate a pathfind algorithm bug","Debug the pathfind v1 graph construction for the affected constraints to find why it returned no steps"],"exampleFix":"// before\nlet path = Path::new(map, steps, requirements);\n// after\nif steps.is_empty() {\n    return Ok(None); // or fall back to another route instead of panicking\n}\nlet path = Path::new(map, steps, requirements);","handlingStrategy":"validation","validationCode":"fn path_is_nonempty(steps: &[PathStep]) -> bool { !steps.is_empty() }\nif !path_is_nonempty(&steps) { return Err(anyhow!(\"pathfind returned no steps\")); }","typeGuard":"fn has_steps(steps: &[PathStep]) -> Option<&[PathStep]> {\n    if steps.is_empty() { None } else { Some(steps) }\n}","tryCatchPattern":null,"preventionTips":["Handle the degenerate start == end request case before calling pathfind","Keep map_model and map files version-matched","Treat any empty pathfind result as a bug to report upstream"],"tags":["rust","pathfinding","panic","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}