a-b-street/abstreet · error · anyhow::Error
couldn't find where shape leaves map
Error message
couldn't find where shape leaves map
What it means
The mirror case of route entry: create_route computes the route's exit point as the last intersection between the raw GTFS shape and the map boundary ring. If there are no intersections at all (so .last() is None), the shape never leaves the map and this error is thrown, preventing selection of an outgoing border.
Solutions
- Fall back to snapping the last shape point to the nearest outgoing border when no intersection exists
- Confirm shape and boundary use identical projections/CRS
- Skip contained routes with a warning rather than failing the import
- If loops are legitimate, special-case them to terminate at the entry border instead
Example fix
// before
let exit_pt = *map.boundary_polygon.get_outer_ring().all_intersections(&route.shape).last().ok_or_else(|| anyhow!("couldn't find where shape leaves map"))?;
// after
let exit_pt = match map.boundary_polygon.get_outer_ring().all_intersections(&route.shape).last() {
Some(pt) => *pt,
None => {
warn!("route {} never leaves the map; reusing entry border as exit", route.route_id);
entry_pt
}
}; Defensive patterns
Strategy: fallback
Validate before calling
let hits = map.boundary_polygon.get_outer_ring().all_intersections(&route.shape);
if hits.is_empty() {
// route neither enters nor leaves; plan border handling up front
} Try / catch
match create_route(...) { Err(e) if e.to_string().contains("shape leaves map") => { warn!("contained route: {}", e); continue; }, r => r } Prevention
- Special-case fully-contained loop routes
- Clip shapes explicitly to a buffered boundary so they always cross it
- Validate feed shapes against the boundary at import time
- Keep projections identical between shapes and map geometry
When it happens
Trigger: Calling finalize_transit on a route whose shape polyline has zero intersections with map.boundary_polygon.get_outer_ring(); the same empty all_intersections result as the entry check, hit at the .last() call.
Common situations: Circular or loop routes entirely contained in the map; feeds where the last trip shape terminates inside the boundary; coordinate projection mismatches; boundary polygon edits that now fully contain the shape.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- couldn't find where shape enters map
- Couldn't find a lane for
- Stop position wasn't close to a sidewalk
- No valid stops
- Couldn't find a border near start
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/30948aa3ff47ee8b.
Report an issue: GitHub.
Appendix: source
Thrown at map_model/src/make/transit.rs:196
Some((l, _)) => l,
None => bail!(
"Couldn't find a {:?} border near start {}",
route.route_type,
entry_pt
),
}
};
let end_border = if map.boundary_polygon.contains_pt(route.shape.last_pt()) {
None
} else {
// Find the last time the route shape hits the map boundary
let exit_pt = *map
.boundary_polygon
.get_outer_ring()
.all_intersections(&route.shape)
.last()
.ok_or_else(|| anyhow!("couldn't find where shape leaves map"))?;
// Snap that to a border
let borders = if route.route_type == RawTransitType::Bus {
&snapper.bus_outgoing_borders
} else {
&snapper.train_outgoing_borders
};
match borders.closest_pt(exit_pt, border_snap_threshold) {
Some((lane, _)) => {
// Edge case: the last stop is on the same road as the border. We can't lane-change
// suddenly, so match the lane in that case.
let last_stop_lane = map.get_ts(*stops.last().unwrap()).driving_pos.lane();
Some(if lane.road == last_stop_lane.road {
last_stop_lane
} else {
lane
})
}
None => bail!(View on GitHub (pinned to 0964f29315)