{"record":{"id":"b8db3ac41c86254e","repo":"a-b-street/abstreet","slug":"doesn-t-contain","errorCode":null,"errorMessage":"{} doesn't contain {}","messagePattern":"(.+?) doesn't contain (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/objects/road.rs","lineNumber":239,"sourceCode":"                allowed_turns: Default::default(),\n            })\n            .collect()\n    }\n\n    pub fn shift_from_left_side(&self, width_from_left_side: Distance) -> Result<PolyLine> {\n        self.center_pts\n            .shift_from_center(self.get_width(), width_from_left_side)\n    }\n\n    /// lane must belong to this road. Offset 0 is the centermost lane on each side of a road, then\n    /// it counts up from there. Note this is a different offset than `offset`!\n    pub(crate) fn dir_and_offset(&self, lane: LaneID) -> (Direction, usize) {\n        for dir in [Direction::Fwd, Direction::Back] {\n            if let Some(idx) = self.children(dir).iter().position(|pair| pair.0 == lane) {\n                return (dir, idx);\n            }\n        }\n        panic!(\"{} doesn't contain {}\", self.id, lane);\n    }\n\n    pub fn parking_to_driving(&self, parking: LaneID) -> Option<LaneID> {\n        self.find_closest_lane(parking, |l| l.is_driving())\n    }\n\n    pub(crate) fn speed_limit_from_osm(&self) -> Speed {\n        if let Some(limit) = self.osm_tags.get(\"maxspeed\") {\n            if let Some(speed) = if let Ok(kmph) = limit.parse::<f64>() {\n                Some(Speed::km_per_hour(kmph))\n            } else if let Some(mph) = limit\n                .strip_suffix(\" mph\")\n                .and_then(|x| x.parse::<f64>().ok())\n            {\n                Some(Speed::miles_per_hour(mph))\n            } else {\n                None\n            } {","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/objects/road.rs#L221-L257","documentation":"Road::dir_and_offset scans both directions' child lane lists for the given LaneID to return its direction and index. Panics when the road contains no such lane, i.e. the lane belongs to a different road.","triggerScenarios":"Calling road.dir_and_offset(lane) with a LaneID that is not a child of that road — e.g. derived from a different road, or from a stale/invalid ID after edits or re-import.","commonSituations":"Lane-offset math in edits and drawing code; mixing up lane IDs between two adjacent roads; loading edits JSON against a regenerated map where IDs shifted.","solutions":["Verify lane belongs to the road: road.children(Direction::Fwd).iter().chain(children(Back)) contains the ID before calling.","Recompute the LaneID from the same road reference rather than caching it.","Check that edits/persisted IDs match the current map version; regenerate or re-target by orig_id."],"exampleFix":"// before\nlet (dir, off) = road.dir_and_offset(lane);\n// after\nif !road.children(Direction::Fwd).iter().chain(road.children(Direction::Back).iter()).any(|(l, _)| *l == lane) {\n    anyhow::bail!(\"{} not in {}\", lane, road.id);\n}\nlet (dir, off) = road.dir_and_offset(lane);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn dir_and_offset_safe(road: &Road, lane: LaneID) -> Option<(Direction, usize)> {\n    for dir in [Direction::Fwd, Direction::Back] {\n        if let Some(idx) = road.children(dir).iter().position(|p| p.0 == lane) {\n            return Some((dir, idx));\n        }\n    }\n    None\n}","tryCatchPattern":null,"preventionTips":["Only pass lane IDs obtained from the same Road object","Re-target persisted edit lane IDs by orig_id after re-import","Unit-test lane-offset helpers against regenerated maps"],"tags":["invariant","wrong-argument","lanes","roads"],"backgroundTag":"invalid-argument-value","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"}