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

  1. Inspect the printed step list to find the first mismatched pair and check the geometry/connectivity of those lanes and turns in the map
  2. Regenerate or re-import the map so lane geometry and turn connectivity are consistent
  3. If caused by recent code changes to pathfind or contraflow handling, revert or fix the edge-construction code
  4. 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

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


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)