a-b-street/abstreet · error
pathfind() returned path that warps
Error message
pathfind() returned path that warps {} from {:?} to {:?} What it means
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.
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
Example fix
// before
let path = Path::new(map, &pathfind_steps, requirements);
// after
let contiguous = pathfind_steps.windows(2).all(|pair| {
end_pt(map, pair[0]).dist_to(start_pt(map, pair[1])) < EPSILON_DIST
});
assert!(contiguous, "pathfind produced a warping path");
let path = Path::new(map, &pathfind_steps, requirements); Defensive patterns
Strategy: validation
Validate before calling
fn steps_contiguous(map: &Map, steps: &[PathStep]) -> bool {
steps.windows(2).all(|p| step_end(map, p[0]).dist_to(step_start(map, p[1])) < EPSILON_DIST)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- PathConstraints::from_lt
- Negative dist_ahead?!
- expected turn, but found
- modify_step broke total_length, it's now
- Empty path
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/62f3d1fe9fa68220.
Report an issue: GitHub.
Appendix: source
Thrown at map_model/src/pathfind/v1.rs:784
println!("All steps in invalid path:");
for s in steps {
match s {
PathStep::Lane(l) => println!(
" {:?} from {} to {}",
s,
map.get_l(*l).src_i,
map.get_l(*l).dst_i
),
PathStep::ContraflowLane(l) => println!(
" {:?} from {} to {}",
s,
map.get_l(*l).dst_i,
map.get_l(*l).src_i
),
PathStep::Turn(_) | PathStep::ContraflowTurn(_) => println!(" {:?}", s),
}
}
panic!(
"pathfind() returned path that warps {} from {:?} to {:?}",
len, pair[0], pair[1]
);
}
}
}
fn validate_restrictions(map: &Map, steps: &[PathStep]) {
for triple in steps.windows(5) {
if let (PathStep::Lane(l1), PathStep::Lane(l2), PathStep::Lane(l3)) =
(triple[0], triple[2], triple[4])
{
let from = map.get_parent(l1);
let via = l2.road;
let to = l3.road;
for (dont_via, dont_to) in &from.complicated_turn_restrictions {
if via == *dont_via && to == *dont_to {View on GitHub (pinned to 0964f29315)