{"record":{"id":"62f3d1fe9fa68220","repo":"a-b-street/abstreet","slug":"pathfind-returned-path-that-warps-from-to","errorCode":null,"errorMessage":"pathfind() returned path that warps {} from {:?} to {:?}","messagePattern":"pathfind\\(\\) returned path that warps (.+?) from (.+?) to (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/pathfind/v1.rs","lineNumber":784,"sourceCode":"            println!(\"All steps in invalid path:\");\n            for s in steps {\n                match s {\n                    PathStep::Lane(l) => println!(\n                        \"  {:?} from {} to {}\",\n                        s,\n                        map.get_l(*l).src_i,\n                        map.get_l(*l).dst_i\n                    ),\n                    PathStep::ContraflowLane(l) => println!(\n                        \"  {:?} from {} to {}\",\n                        s,\n                        map.get_l(*l).dst_i,\n                        map.get_l(*l).src_i\n                    ),\n                    PathStep::Turn(_) | PathStep::ContraflowTurn(_) => println!(\"  {:?}\", s),\n                }\n            }\n            panic!(\n                \"pathfind() returned path that warps {} from {:?} to {:?}\",\n                len, pair[0], pair[1]\n            );\n        }\n    }\n}\n\nfn validate_restrictions(map: &Map, steps: &[PathStep]) {\n    for triple in steps.windows(5) {\n        if let (PathStep::Lane(l1), PathStep::Lane(l2), PathStep::Lane(l3)) =\n            (triple[0], triple[2], triple[4])\n        {\n            let from = map.get_parent(l1);\n            let via = l2.road;\n            let to = l3.road;\n\n            for (dont_via, dont_to) in &from.complicated_turn_restrictions {\n                if via == *dont_via && to == *dont_to {","sourceCodeStart":766,"sourceCodeEnd":802,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/pathfind/v1.rs#L766-L802","documentation":"validate_continuity checks that consecutive PathSteps in a produced path connect geometrically: the end point of one step must coincide (within EPSILON_DIST) with the start of the next. When the gap exceeds the epsilon, the path 'warps' through space, meaning the pathfinder stitched together steps that don't actually touch. This is an internal consistency check on pathfind output, surfaced via panic in Path::new.","triggerScenarios":"Path::new called on pathfind output where adjacent steps (lanes, contraflow lanes, turns) have mismatched endpoints — typically after lane reversal/contraflow changes, map edits, or bugs in the v1 pathfind graph edge weights.","commonSituations":"Seen when testing map edits that flip lane direction, import modified OSM data, or when debugging custom pathfinding changes; the panic prints all steps to help locate the warp.","solutions":["Inspect the printed step list to find the first mismatched pair and check the geometry/connectivity of those lanes and turns in the map","Regenerate or re-import the map so lane geometry and turn connectivity are consistent","If caused by recent code changes to pathfind or contraflow handling, revert or fix the edge-construction code","Report upstream with the map and request if it reproduces on stock maps"],"exampleFix":"// before\nlet path = Path::new(map, &pathfind_steps, requirements);\n// after\nlet contiguous = pathfind_steps.windows(2).all(|pair| {\n    end_pt(map, pair[0]).dist_to(start_pt(map, pair[1])) < EPSILON_DIST\n});\nassert!(contiguous, \"pathfind produced a warping path\");\nlet path = Path::new(map, &pathfind_steps, requirements);","handlingStrategy":"validation","validationCode":"fn steps_contiguous(map: &Map, steps: &[PathStep]) -> bool {\n    steps.windows(2).all(|p| step_end(map, p[0]).dist_to(step_start(map, p[1])) < EPSILON_DIST)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid edits that reverse or flip lanes without regenerating turns","Re-verify turn connectivity after importing new OSM data","Run path validation on sample requests after map edits"],"tags":["rust","pathfinding","panic","geometry"],"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"}