a-b-street/abstreet · error
Started on a road we shouldn't trace
Error message
Started on a road we shouldn't trace
What it means
Perimeter::single_block traces a block perimeter starting from a lane, but the caller supplied a `skip` set and the starting lane's road is in it. The library refuses to begin tracing a road it was explicitly told to avoid (typically bridges/tunnels), so it bails immediately rather than produce a wrong perimeter.
Solutions
- Check `skip.contains(&map.get_l(start).get_nearest_side_of_road(map).road)` before calling and pick a different start lane.
- Choose a start lane on a road not in the skip set (iterate candidate lanes and skip filtered ones).
- If the road must be traced, remove that RoadID from the skip set.
Example fix
// before
let perimeter = Perimeter::single_block(map, start, &skip)?;
// after
let start_side = map.get_l(start).get_nearest_side_of_road(map);
if skip.contains(&start_side.road) {
start = pick_lane_not_on_skipped_roads(map, &skip);
}
let perimeter = Perimeter::single_block(map, start, &skip)?; Defensive patterns
Strategy: validation
Validate before calling
let start_side = map.get_l(start).get_nearest_side_of_road(map);
anyhow::ensure!(!skip.contains(&start_side.road), "start lane {:?} is on a skipped road", start); Try / catch
match Perimeter::single_block(map, start, &skip) {
Ok(p) => use(p),
Err(_) => retry_with_different_start_lane(),
} Prevention
- Pick start lanes from roads already filtered against the skip set.
- When reusing start lanes from cached runs, revalidate against the current skip set.
When it happens
Trigger: Calling Perimeter::single_block(map, start_lane, &skip) where the road containing `start_lane` is a member of `skip` — i.e. the chosen start lane's nearest road side is one of the roads the caller excluded from tracing.
Common situations: FindBlocks passes a precomputed skip set (tunnels, bridges, tagged untraced roads) and the randomly or externally chosen start lane happens to lie on one of those roads; callers reusing a start lane from a previous run after the skip set changed.
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
- Starting on inner piece of a loop road
- hit the map boundary at
- Looped back on the same road, but not at a dead-end
- Infinite loop starting from
- No common roads
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/afa184feb0262242.
Report an issue: GitHub.
Appendix: source
Thrown at blockfinding/src/lib.rs:52
// intersections or possibly by water/park areas.
#[derive(Clone, Serialize, Deserialize)]
pub struct Perimeter {
pub roads: Vec<RoadSideID>,
/// These roads exist entirely within the perimeter
pub interior: BTreeSet<RoadID>,
}
impl Perimeter {
/// Starting at any lane, snap to the nearest side of that road, then begin tracing a single
/// block, with no interior roads. This will fail if a map boundary is reached. The results are
/// unusual when crossing the entrance to a tunnel or bridge, and so `skip` is used to avoid
/// tracing there.
pub fn single_block(map: &Map, start: LaneID, skip: &HashSet<RoadID>) -> Result<Perimeter> {
let mut roads = Vec::new();
let start_road_side = map.get_l(start).get_nearest_side_of_road(map);
if skip.contains(&start_road_side.road) {
bail!("Started on a road we shouldn't trace");
}
// We may start on a loop road on the "inner" direction
{
let start_r = map.get_parent(start);
if start_r.src_i == start_r.dst_i {
let i = map.get_i(start_r.src_i);
if !i.get_road_sides_sorted(map).contains(&start_road_side) {
bail!("Starting on inner piece of a loop road");
}
}
}
// We need to track which side of the road we're at, but also which direction we're facing
let mut current_road_side = start_road_side;
let mut current_intersection = map.get_l(start).dst_i;
loop {
let i = map.get_i(current_intersection);View on GitHub (pinned to 0964f29315)