a-b-street/abstreet · error

Empty path

Error message

Empty path

What it means

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.

Solutions

  1. Check whether start and end of the PathRequest are identical or effectively the same position and handle that case before calling pathfind
  2. Update map_model / regenerate the map so the map version matches the pathfind code, since graph edits can desynchronize the algorithm
  3. Report upstream with the PathRequest and map file; empty results indicate a pathfind algorithm bug
  4. Debug the pathfind v1 graph construction for the affected constraints to find why it returned no steps

Example fix

// before
let path = Path::new(map, steps, requirements);
// after
if steps.is_empty() {
    return Ok(None); // or fall back to another route instead of panicking
}
let path = Path::new(map, steps, requirements);
Defensive patterns

Strategy: validation

Validate before calling

fn path_is_nonempty(steps: &[PathStep]) -> bool { !steps.is_empty() }
if !path_is_nonempty(&steps) { return Err(anyhow!("pathfind returned no steps")); }

Type guard

fn has_steps(steps: &[PathStep]) -> Option<&[PathStep]> {
    if steps.is_empty() { None } else { Some(steps) }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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/8602578d276263e9. Report an issue: GitHub.

Appendix: source

Thrown at map_model/src/pathfind/v1.rs:749

                map.get_l(req.end.lane()).get_directed_parent(),
            );
            let pair = common.entry(key).or_insert_with(|| (req, 0));
            pair.1 += 1;
        }
        if false {
            info!(
                "{} requests deduplicated down to {}",
                prettyprint_usize(count_before),
                prettyprint_usize(common.len())
            );
        }
        common.into_values().collect()
    }
}

fn validate_continuity(map: &Map, steps: &[PathStep]) {
    if steps.is_empty() {
        panic!("Empty path");
    }
    for pair in steps.windows(2) {
        let from = match pair[0] {
            PathStep::Lane(id) => map.get_l(id).last_pt(),
            PathStep::ContraflowLane(id) => map.get_l(id).first_pt(),
            PathStep::Turn(id) => map.get_t(id).geom.last_pt(),
            PathStep::ContraflowTurn(id) => map.get_t(id).geom.first_pt(),
        };
        let to = match pair[1] {
            PathStep::Lane(id) => map.get_l(id).first_pt(),
            PathStep::ContraflowLane(id) => map.get_l(id).last_pt(),
            PathStep::Turn(id) => map.get_t(id).geom.first_pt(),
            PathStep::ContraflowTurn(id) => map.get_t(id).geom.last_pt(),
        };
        let len = from.dist_to(to);
        if len > EPSILON_DIST {
            println!("All steps in invalid path:");
            for s in steps {

View on GitHub (pinned to 0964f29315)