{"record":{"id":"e6dff06c85bef83f","repo":"a-b-street/abstreet","slug":"turns-for-orphan-some-lanes-incoming-outgoing","errorCode":null,"errorMessage":"Turns for {} orphan some lanes. Incoming: {:?}, outgoing: {:?}","messagePattern":"Turns for (.+?) orphan some lanes\\. Incoming: (.+?), outgoing: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/make/turns.rs","lineNumber":131,"sourceCode":"    for turn in turns {\n        let src_lt = map.get_l(turn.id.src).lane_type;\n        let dst_lt = map.get_l(turn.id.dst).lane_type;\n\n        if src_lt == dst_lt {\n            incoming_missing.remove(&turn.id.src);\n            outgoing_missing.remove(&turn.id.dst);\n        }\n\n        if src_lt == LaneType::Biking || src_lt == LaneType::Bus {\n            incoming_missing.remove(&turn.id.src);\n        }\n        if dst_lt == LaneType::Biking || dst_lt == LaneType::Bus {\n            outgoing_missing.remove(&turn.id.dst);\n        }\n    }\n\n    if !incoming_missing.is_empty() || !outgoing_missing.is_empty() {\n        bail!(\n            \"Turns for {} orphan some lanes. Incoming: {:?}, outgoing: {:?}\",\n            i.id,\n            incoming_missing,\n            outgoing_missing\n        );\n    }\n    Ok(())\n}\n\nfn make_vehicle_turns(i: &Intersection, map: &Map) -> Vec<Turn> {\n    let mut turns = Vec::new();\n\n    // Just generate every possible combination of turns between incoming and outgoing lanes.\n    let is_deadend = i.is_deadend_for_driving(map);\n    for src in &i.incoming_lanes {\n        let src = map.get_l(*src);\n        if !src.lane_type.is_for_moving_vehicles() {\n            continue;","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/make/turns.rs#L113-L149","documentation":"After generating turns for an intersection, every driving/biking/bus lane must have at least one incoming and one outgoing turn, otherwise vehicles could get trapped. verify_vehicle_connectivity bails listing the orphaned incoming and outgoing lanes when connectivity for intersection i is incomplete.","triggerScenarios":"make_all_turns -> verify_vehicle_connectivity where an intersection's lane types (e.g. driving lanes with no connecting turns, or dead-end geometry) leave lanes without turns — commonly at one-way oddities, dead-ends, or intersections with unusual lane type mixes.","commonSituations":"OSM intersections where a driving lane dead-ends; one-way streets into intersections with no exit lanes; newly-supported lane types (bus/bike) not fully wired by turn generation.","solutions":["Inspect the listed incoming/outgoing lane ids and fix the OSM geometry so every drivable lane connects to a turn.","Check turn-generation filtering rules for the lane types involved (driving/biking/bus).","If the orphan is genuinely a dead-end (allowed), adjust the connectivity check to whitelist it or change the lane's type in map generation."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let orphans = incoming_missing.len() + outgoing_missing.len();\nif orphans > 0 { /* fix geometry or whitelist the dead-end before make_all_turns */ }","typeGuard":null,"tryCatchPattern":"match make_all_turns(map) {\n    Err(e) if e.to_string().contains(\"orphan some lanes\") => {\n        // inspect e for the lane ids; repair input OSM or adjust lane types\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Fix dead-end driving lanes and one-way oddities in OSM before import","Keep lane-type handling (bus/bike) in sync with turn-generation rules","Run map generation on small extract areas first to catch orphaned lanes early"],"tags":["map-import","turns","connectivity"],"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-23T08:17:48.524Z"}