{"record":{"id":"b7bbe0c0b77f3d2c","repo":"a-b-street/abstreet","slug":"must-get-sidewalk-broken-by-found-lanes","errorCode":null,"errorMessage":"must_get_sidewalk broken by {} ({}). Found lanes {:?}","messagePattern":"must_get_sidewalk broken by (.+?) \\((.+?)\\)\\. Found lanes (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/objects/road.rs","lineNumber":106,"sourceCode":"        }\n    }\n\n    /// Strict for bikes. If there are bike lanes, not allowed to use other lanes.\n    pub fn lanes(self, constraints: PathConstraints, map: &Map) -> Vec<LaneID> {\n        let r = map.get_r(self.road);\n        constraints.filter_lanes(r.children(self.dir).iter().map(|(l, _)| *l).collect(), map)\n    }\n\n    /// Get the only sidewalk or shoulder on this side of the road, and panic otherwise.\n    pub fn must_get_sidewalk(self, map: &Map) -> LaneID {\n        let mut found = Vec::new();\n        for (l, lt) in map.get_r(self.road).children(self.dir) {\n            if lt.is_walkable() {\n                found.push(l);\n            }\n        }\n        if found.len() != 1 {\n            panic!(\n                \"must_get_sidewalk broken by {} ({}). Found lanes {:?}\",\n                self,\n                map.get_r(self.road).orig_id,\n                found\n            );\n        }\n        found[0]\n    }\n\n    /// Does this directed road have any lanes of a certain type?\n    pub fn has_lanes(self, lane_type: LaneType, map: &Map) -> bool {\n        for (_, lt) in map.get_r(self.road).children(self.dir) {\n            if lt == lane_type {\n                return true;\n            }\n        }\n        false\n    }","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/objects/road.rs#L88-L124","documentation":"DirectedRoadID::must_get_sidewalk asserts a directed road has exactly one walkable child lane. The invariant breaks if a road has zero or multiple walkable lanes (e.g. two sidewalks or a footway merged into the road's children), so it panics listing the found lanes.","triggerScenarios":"Calling must_get_sidewalk on a road whose lane list contains 0 or >1 walkable lanes in the given direction — commonly after map edits (parking-to-sidewalk conversions) or on oddly tagged OSM ways.","commonSituations":"Pedestrian routing and SidewalkPOC/traversal code paths that assume one sidewalk per road side; user edits (e.g. through the map editor) converting car lanes to sidewalks.","solutions":["Inspect the listed lanes; find which edit or import step created the extra/missing walkable lane and revert it.","Use Road::children / filter for walkable lanes instead of assuming exactly one, and pick the nearest.","Fix OSM tags so each side of the road has at most one sidewalk.","Replace must_get_sidewalk usages with find_closest_lane(|l| l.is_walkable()) in your own code paths."],"exampleFix":"// before\nlet sidewalk = dir_road.must_get_sidewalk(map);\n// after\nif let Some(l) = map.get_r(dir_road.road).find_closest_lane(dir_road.lane_id, |l| l.is_walkable(), map) { /* use l */ } else { anyhow::bail!(\"no sidewalk on {}\", dir_road.road) };","handlingStrategy":"validation","validationCode":"// count walkable children before calling\nlet walkable: Vec<_> = map.get_r(dir.road).children(dir.dir).iter()\n    .filter(|(_, lt)| lt.is_walkable()).collect();\nassert_eq!(walkable.len(), 1, \"road {} has {} walkable lanes\", dir.road, walkable.len());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer find_closest_lane with an is_walkable filter over must_get helpers","Review map edits that convert car lanes to sidewalks","Validate imported maps for multi-sidewalk roads before running sims"],"tags":["invariant","pedestrian","roads","map-edits"],"backgroundTag":"internal-invariant-violation","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"}