a-b-street/abstreet · error

doesn't contain both and

Error message

{} doesn't contain both {} and {}

What it means

get_lanes_between walks the road's ordered child lanes and collects all lanes between lanes l1 and l2 (inclusive by id match). Panics when the scan finishes without having matched both lane IDs, meaning at least one lane isn't a child of this road.

Solutions

  1. Confirm both l1 and l2 are children of self.id before calling (scan children lists).
  2. Re-resolve the lane pair from current map state (e.g. by lane type and offset) instead of cached IDs.
  3. Update or discard stale edits JSON that references regenerated lane IDs.

Example fix

// before
let lanes = road.get_lanes_between(a, b);
// after
let kids: Vec<_> = road.children(Direction::Fwd).iter().chain(road.children(Direction::Back).iter()).map(|(l, _)| *l).collect();
if !kids.contains(&a) || !kids.contains(&b) { anyhow::bail!("lanes not on {}", road.id); }
let lanes = road.get_lanes_between(a, b);
Defensive patterns

Strategy: validation

Validate before calling

// verify both lanes belong to the road first
let kids: Vec<LaneID> = road.children(Direction::Fwd).iter().chain(road.children(Direction::Back).iter()).map(|(l, _)| *l).collect();
if !kids.contains(&l1) || !kids.contains(&l2) { return Err(anyhow!("lanes not on road {}", road.id)); }

Prevention

When it happens

Trigger: Calling road.get_lanes_between(l1, l2) where either lane belongs to a different road, or IDs are stale relative to the current map (edits applied, lanes merged/deleted).

Common situations: Edit code computing the range of lanes to modify (e.g. lane-type changes between two driving lanes); using persisted lane IDs from an older map version.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at map_model/src/objects/road.rs:617

            });
        }
    }

    /// Returns all lanes located between l1 and l2, exclusive.
    pub fn get_lanes_between(&self, l1: LaneID, l2: LaneID) -> Vec<LaneID> {
        let mut results = Vec::new();
        let mut found_start = false;
        for l in &self.lanes {
            if found_start {
                if l.id == l1 || l.id == l2 {
                    return results;
                }
                results.push(l.id);
            } else if l.id == l1 || l.id == l2 {
                found_start = true;
            }
        }
        panic!("{} doesn't contain both {} and {}", self.id, l1, l2);
    }

    /// A simple classification of if the directed road is stressful or not for cycling. Arterial
    /// roads without a bike lane match this. Why arterial, instead of looking at speed limits?
    /// Even on arterial roads with official speed limits lowered, in practice vehicles still
    /// travel at the speed suggested by the design of the road.
    // TODO Should elevation matter or not? Flat high-speed roads are still terrifying, but there's
    // something about slogging up (or flying down!) a pothole-filled road inches from cars.
    pub fn high_stress_for_bikes(&self, map: &Map, dir: Direction) -> bool {
        let mut bike_lanes = false;
        let mut can_use = false;
        // Can a bike even use it, or is it a highway?
        for l in &self.lanes {
            if l.lane_type == LaneType::Biking && l.dir == dir {
                bike_lanes = true;
            }
            if PathConstraints::Bike.can_use(l, map) {
                can_use = true;

View on GitHub (pinned to 0964f29315)