{"record":{"id":"7a1270e45c692132","repo":"a-b-street/abstreet","slug":"can-t-transform-a-road-based-path-to-a-lane-based-path-for","errorCode":null,"errorMessage":"Can't transform a road-based path to a lane-based path for {}","messagePattern":"Can't transform a road-based path to a lane-based path for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/pathfind/v2.rs","lineNumber":293,"sourceCode":"                    }));\n                }\n                steps.push(PathStep::Lane(self.req.end.lane()));\n                let mut blocked_starts = Vec::new();\n                if steps[0] != PathStep::Lane(self.orig_start_lane) {\n                    let actual_start = match steps[0] {\n                        PathStep::Lane(l) => l,\n                        _ => unreachable!(),\n                    };\n                    blocked_starts.push(self.orig_start_lane);\n                    blocked_starts\n                        .extend(start_road.get_lanes_between(self.orig_start_lane, actual_start));\n                    // Sometimes a no-op for exiting off-side\n                    self.req.start = self.req.start.equiv_pos(actual_start, map);\n                }\n                let uber_turns = find_uber_turns(&steps, map, self.uber_turns);\n                Ok(Path::new(map, steps, self.req, uber_turns, blocked_starts))\n            }\n            None => bail!(\n                \"Can't transform a road-based path to a lane-based path for {}\",\n                self.req\n            ),\n        }\n    }\n\n    fn into_v1_walking(self, map: &Map) -> Result<Path> {\n        let mut steps = Vec::new();\n        for step in self.steps {\n            steps.push(match step {\n                PathStepV2::Along(r) => PathStep::Lane(r.must_get_sidewalk(map)),\n                PathStepV2::Contraflow(r) => PathStep::ContraflowLane(r.must_get_sidewalk(map)),\n                PathStepV2::Movement(mvmnt) => PathStep::Turn(TurnID {\n                    src: mvmnt.from.must_get_sidewalk(map),\n                    dst: mvmnt.to.must_get_sidewalk(map),\n                    parent: mvmnt.parent,\n                }),\n                PathStepV2::ContraflowMovement(mvmnt) => PathStep::ContraflowTurn(TurnID {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/pathfind/v2.rs#L275-L311","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet v1 = old_v2_path.into_v1(&map)?;\n// after\nlet v1 = map.pathfind(old_v2_path.get_req())?; // recompute at lane level","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let v1 = match v2_path.into_v1(&map) {\n    Ok(p) => p,\n    Err(e) if e.to_string().starts_with(\"Can't transform a road-based path\") => {\n        map.pathfind(v2_path.get_req())? // recompute fresh lane-level path\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["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."],"tags":["pathfinding","conversion","path-v2","map-model"],"backgroundTag":"unsupported-operation","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"}