a-b-street/abstreet · error

Turns for orphan some lanes. Incoming: , outgoing

Error message

Turns for {} orphan some lanes. Incoming: {:?}, outgoing: {:?}

What it means

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.

Solutions

  1. Inspect the listed incoming/outgoing lane ids and fix the OSM geometry so every drivable lane connects to a turn.
  2. Check turn-generation filtering rules for the lane types involved (driving/biking/bus).
  3. 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.
Defensive patterns

Strategy: validation

Validate before calling

let orphans = incoming_missing.len() + outgoing_missing.len();
if orphans > 0 { /* fix geometry or whitelist the dead-end before make_all_turns */ }

Try / catch

match make_all_turns(map) {
    Err(e) if e.to_string().contains("orphan some lanes") => {
        // inspect e for the lane ids; repair input OSM or adjust lane types
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/e6dff06c85bef83f. Report an issue: GitHub.

Appendix: source

Thrown at map_model/src/make/turns.rs:131

    for turn in turns {
        let src_lt = map.get_l(turn.id.src).lane_type;
        let dst_lt = map.get_l(turn.id.dst).lane_type;

        if src_lt == dst_lt {
            incoming_missing.remove(&turn.id.src);
            outgoing_missing.remove(&turn.id.dst);
        }

        if src_lt == LaneType::Biking || src_lt == LaneType::Bus {
            incoming_missing.remove(&turn.id.src);
        }
        if dst_lt == LaneType::Biking || dst_lt == LaneType::Bus {
            outgoing_missing.remove(&turn.id.dst);
        }
    }

    if !incoming_missing.is_empty() || !outgoing_missing.is_empty() {
        bail!(
            "Turns for {} orphan some lanes. Incoming: {:?}, outgoing: {:?}",
            i.id,
            incoming_missing,
            outgoing_missing
        );
    }
    Ok(())
}

fn make_vehicle_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
    let mut turns = Vec::new();

    // Just generate every possible combination of turns between incoming and outgoing lanes.
    let is_deadend = i.is_deadend_for_driving(map);
    for src in &i.incoming_lanes {
        let src = map.get_l(*src);
        if !src.lane_type.is_for_moving_vehicles() {
            continue;

View on GitHub (pinned to 0964f29315)