a-b-street/abstreet · error
Can't transform a road-based path to a lane-based path for
Error message
Can't transform a road-based path to a lane-based path for {} What it means
PathV2 stores road-level steps; into_v1 converts it to a lane-level PathV1 by resolving each road step to concrete lanes via an internal lookup. When that lookup returns None, the road-level sequence cannot be refined into lane-level steps, so conversion bails. It indicates the v2 path lacks the resolution data needed for lane-level execution.
Solutions
- Re-run the pathfinder to produce a fresh v2 path (or a v1 path directly) instead of converting a stale one.
- Don't call into_v1 unless the path was created with lane-level detail; check the path's origin/provenance.
- Migrate persisted paths to the current format after map/model version changes.
- If conversion should always work, ensure the path was created via map.pathfind with the same request and current map.
Example fix
// before let v1 = old_v2_path.into_v1(&map)?; // after let v1 = map.pathfind(old_v2_path.get_req())?; // recompute at lane level
Defensive patterns
Strategy: fallback
Try / catch
let v1 = match v2_path.into_v1(&map) {
Ok(p) => p,
Err(e) if e.to_string().starts_with("Can't transform a road-based path") => {
map.pathfind(v2_path.get_req())? // recompute fresh lane-level path
}
Err(e) => return Err(e),
}; Prevention
- Recompute paths after map/model upgrades instead of converting persisted ones.
- Only call into_v1 on paths that came from the current pathfinder.
- If lane-level detail is always needed, use the v1 pathfinder or request resolution at creation time.
When it happens
Trigger: Calling PathV2::into_v1 (map_model/src/pathfind/v2.rs:293) on a path whose optional lane-detail cache/entry is None — i.e. the v2 path was produced without lane-level resolution for this request.
Common situations: Mixing path versions after a map upgrade (old persisted v2 paths), constructing PathV2 manually without full resolution, or paths created in a context where lane details were pruned to save memory.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- 0 dist ahead for slice
- get_step_at_dist_along has leftover distance of
- doesn't point to
- PathConstraints::from_lt
- Negative dist_ahead?!
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/7a1270e45c692132.
Report an issue: GitHub.
Appendix: source
Thrown at map_model/src/pathfind/v2.rs:293
}));
}
steps.push(PathStep::Lane(self.req.end.lane()));
let mut blocked_starts = Vec::new();
if steps[0] != PathStep::Lane(self.orig_start_lane) {
let actual_start = match steps[0] {
PathStep::Lane(l) => l,
_ => unreachable!(),
};
blocked_starts.push(self.orig_start_lane);
blocked_starts
.extend(start_road.get_lanes_between(self.orig_start_lane, actual_start));
// Sometimes a no-op for exiting off-side
self.req.start = self.req.start.equiv_pos(actual_start, map);
}
let uber_turns = find_uber_turns(&steps, map, self.uber_turns);
Ok(Path::new(map, steps, self.req, uber_turns, blocked_starts))
}
None => bail!(
"Can't transform a road-based path to a lane-based path for {}",
self.req
),
}
}
fn into_v1_walking(self, map: &Map) -> Result<Path> {
let mut steps = Vec::new();
for step in self.steps {
steps.push(match step {
PathStepV2::Along(r) => PathStep::Lane(r.must_get_sidewalk(map)),
PathStepV2::Contraflow(r) => PathStep::ContraflowLane(r.must_get_sidewalk(map)),
PathStepV2::Movement(mvmnt) => PathStep::Turn(TurnID {
src: mvmnt.from.must_get_sidewalk(map),
dst: mvmnt.to.must_get_sidewalk(map),
parent: mvmnt.parent,
}),
PathStepV2::ContraflowMovement(mvmnt) => PathStep::ContraflowTurn(TurnID {View on GitHub (pinned to 0964f29315)