a-b-street/abstreet · error

must_get_sidewalk broken by

Error message

must_get_sidewalk broken by {} ({}). Found lanes {:?}

What it means

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.

Solutions

  1. Inspect the listed lanes; find which edit or import step created the extra/missing walkable lane and revert it.
  2. Use Road::children / filter for walkable lanes instead of assuming exactly one, and pick the nearest.
  3. Fix OSM tags so each side of the road has at most one sidewalk.
  4. Replace must_get_sidewalk usages with find_closest_lane(|l| l.is_walkable()) in your own code paths.

Example fix

// before
let sidewalk = dir_road.must_get_sidewalk(map);
// after
if 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) };
Defensive patterns

Strategy: validation

Validate before calling

// count walkable children before calling
let walkable: Vec<_> = map.get_r(dir.road).children(dir.dir).iter()
    .filter(|(_, lt)| lt.is_walkable()).collect();
assert_eq!(walkable.len(), 1, "road {} has {} walkable lanes", dir.road, walkable.len());

Prevention

When it happens

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

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

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/b7bbe0c0b77f3d2c. Report an issue: GitHub.

Appendix: source

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

        }
    }

    /// Strict for bikes. If there are bike lanes, not allowed to use other lanes.
    pub fn lanes(self, constraints: PathConstraints, map: &Map) -> Vec<LaneID> {
        let r = map.get_r(self.road);
        constraints.filter_lanes(r.children(self.dir).iter().map(|(l, _)| *l).collect(), map)
    }

    /// Get the only sidewalk or shoulder on this side of the road, and panic otherwise.
    pub fn must_get_sidewalk(self, map: &Map) -> LaneID {
        let mut found = Vec::new();
        for (l, lt) in map.get_r(self.road).children(self.dir) {
            if lt.is_walkable() {
                found.push(l);
            }
        }
        if found.len() != 1 {
            panic!(
                "must_get_sidewalk broken by {} ({}). Found lanes {:?}",
                self,
                map.get_r(self.road).orig_id,
                found
            );
        }
        found[0]
    }

    /// Does this directed road have any lanes of a certain type?
    pub fn has_lanes(self, lane_type: LaneType, map: &Map) -> bool {
        for (_, lt) in map.get_r(self.road).children(self.dir) {
            if lt == lane_type {
                return true;
            }
        }
        false
    }

View on GitHub (pinned to 0964f29315)