a-b-street/abstreet · warning

hit the map boundary at

Error message

hit the map boundary at {}

What it means

While walking the perimeter intersection by intersection, single_block reached a border intersection on the edge of the map. A block perimeter cannot be closed there, so tracing aborts and reports the boundary intersection's original OSM ID. This is expected behavior — perimeters touching the map edge are simply not produced.

Solutions

  1. Accept the failure and skip blocks that touch the map boundary (find_blocks treats these as non-errors by design).
  2. Import a larger map area so the blocks of interest don't touch the border.
  3. Add boundary roads to the `skip` set so traces route around the border.
Defensive patterns

Strategy: try-catch

Validate before calling

let dst_i = map.get_l(start).dst_i;
if map.get_i(dst_i).is_border() { /* start leads straight to boundary; skip this block */ }

Try / catch

match Perimeter::single_block(map, start, &skip) {
    Ok(p) => blocks.push(p),
    Err(e) if e.to_string().starts_with("hit the map boundary") => {}, // expected, skip block
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Any single_block call whose trace path reaches an intersection where is_border() is true — i.e. the block being traced touches the clipped edge of the imported map.

Common situations: Blocks adjacent to the boundary of a downloaded/clipped OSM extract; running blockfinding on small map areas cut out of a larger city; maps missing water/park boundary clipping.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at blockfinding/src/lib.rs:72

        // 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);
            if i.is_border() {
                bail!("hit the map boundary at {}", i.orig_id);
            }
            let mut sorted_roads = i.get_road_sides_sorted(map);
            sorted_roads.retain(|id| !skip.contains(&id.road));

            let idx = sorted_roads
                .iter()
                .position(|x| *x == current_road_side)
                .unwrap() as isize;
            // Do we go clockwise or counter-clockwise around the intersection? Well, unless we're
            // at a dead-end, we want to avoid the other side of the same road.
            let mut next = *wraparound_get(&sorted_roads, idx + 1);
            assert_ne!(next, current_road_side);
            if next.road == current_road_side.road {
                next = *wraparound_get(&sorted_roads, idx - 1);
                assert_ne!(next, current_road_side);
                if next.road == current_road_side.road {
                    if sorted_roads.len() != 2 {
                        bail!("Looped back on the same road, but not at a dead-end");

View on GitHub (pinned to 0964f29315)