a-b-street/abstreet · error
doesn't have an endpoint at
Error message
{} doesn't have an endpoint at {} What it means
Road::incoming_lanes returns the lanes whose traffic enters the given intersection along this road: children_backwards if i is the source, children_forwards if i is the destination. Panics when i isn't an endpoint, since there's no valid direction into it.
Solutions
- Assert src_i == i || dst_i == i before calling, or derive i from the road's endpoints.
- Fix the caller's adjacency iteration so only roads incident to i are processed.
- Re-lookup IDs against the current map rather than reusing persisted ones.
Example fix
// before
let lanes = road.incoming_lanes(i);
// after
if road.src_i != i && road.dst_i != i { anyhow::bail!("road {} has no endpoint at {}", road.id, i); }
let lanes = road.incoming_lanes(i); Defensive patterns
Strategy: type-guard
Type guard
fn incoming_lanes_safe(road: &Road, i: IntersectionID) -> Option<Vec<(LaneID, LaneType)>> {
if road.src_i == i { Some(road.children_backwards()) }
else if road.dst_i == i { Some(road.children_forwards()) }
else { None }
} Prevention
- Only iterate (road, intersection) pairs where the road is incident to the intersection
- Prefer children_forwards/backwards directly when direction is known
- Re-lookup intersection IDs after any re-import or edit application
When it happens
Trigger: Calling road.incoming_lanes(i) with an intersection that is neither src_i nor dst_i — usually in movement/turn generation or signal-building code that iterates the wrong intersection set.
Common situations: Intersection geometry and traffic-signal generation during import; custom movement queries; stale intersection IDs after re-import.
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
- doesn't touch
- doesn't point to
- isn't an endpoint of
- doesn't contain
- Some IndividTrip wasn't associated with a Person?!
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/3d7e3862b658ad12.
Report an issue: GitHub.
Appendix: source
Thrown at map_model/src/objects/road.rs:698
}
// TODO Deprecated
pub(crate) fn children(&self, dir: Direction) -> Vec<(LaneID, LaneType)> {
if dir == Direction::Fwd {
self.children_forwards()
} else {
self.children_backwards()
}
}
/// Returns lanes from the "center" going out
pub(crate) fn incoming_lanes(&self, i: IntersectionID) -> Vec<(LaneID, LaneType)> {
if self.src_i == i {
self.children_backwards()
} else if self.dst_i == i {
self.children_forwards()
} else {
panic!("{} doesn't have an endpoint at {}", self.id, i);
}
}
}
/// Refers to a road segment between two nodes, using OSM IDs. Note OSM IDs are not stable over
/// time and the relationship between a road/intersection and way/node isn't 1:1 at all.
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OriginalRoad {
pub osm_way_id: osm::WayID,
pub i1: osm::NodeID,
pub i2: osm::NodeID,
}
impl fmt::Display for OriginalRoad {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"OriginalRoad({} from {} to {}",View on GitHub (pinned to 0964f29315)