a-b-street/abstreet · error
isn't an endpoint of
Error message
{} isn't an endpoint of {} What it means
Lane::endpoint returns the first or last point of the lane depending on which intersection is requested. Panics when the given IntersectionID is neither the lane's source nor destination intersection, i.e. the lane does not touch that intersection.
Solutions
- Verify the intersection is an endpoint: check lane.src_i or lane.dst_i before calling endpoint.
- Use lane.src_i or lane.dst_i directly instead of an assumed intersection.
- Do not persist LaneID/IntersectionID across map reloads; look them up by stable identifiers each time.
- Check caller logic (crosswalk generation, edits) that pairs lanes with intersections.
Example fix
// before
let pt = lane.endpoint(some_i);
// after
assert!(lane.src_i == some_i || lane.dst_i == some_i, "lane {} not at {}", lane.id, some_i);
let pt = lane.endpoint(some_i); Defensive patterns
Strategy: type-guard
Type guard
fn lane_endpoint_ok(lane: &Lane, i: IntersectionID) -> Option<Pt2D> {
if i == lane.src_i { Some(lane.first_pt()) }
else if i == lane.dst_i { Some(lane.last_pt()) }
else { None }
} Prevention
- Never cache LaneID/IntersectionID across map reloads
- Derive intersections from lane.src_i/dst_i instead of parallel loops
- Use Option-returning helpers instead of panicking APIs in new code
When it happens
Trigger: Calling lane.endpoint(i) with an IntersectionID that is not lane.src_i or lane.dst_i — e.g. passing the wrong intersection from a turn-building loop or using a stale ID after edits/regeneration.
Common situations: Crosswalk or shared-sidewalk-corner construction (make_crosswalk, make_shared_sidewalk_corner) iterating wrong lane sets; using lane IDs from an old map after re-import, since IDs are not stable.
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 contain
- ( ) is a border, but is connected to >1 road
- doesn't touch
- doesn't point to
- doesn't contain both and
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/444ee56813235324.
Report an issue: GitHub.
Appendix: source
Thrown at map_model/src/objects/lane.rs:114
self.lane_center_pts.first_pt()
}
pub fn last_pt(&self) -> Pt2D {
self.lane_center_pts.last_pt()
}
pub fn first_line(&self) -> Line {
self.lane_center_pts.first_line()
}
pub fn last_line(&self) -> Line {
self.lane_center_pts.last_line()
}
pub fn endpoint(&self, i: IntersectionID) -> Pt2D {
if i == self.src_i {
self.first_pt()
} else if i == self.dst_i {
self.last_pt()
} else {
panic!("{} isn't an endpoint of {}", i, self.id);
}
}
/// pt2 will be endpoint
pub fn end_line(&self, i: IntersectionID) -> Line {
if i == self.src_i {
self.first_line().reversed()
} else if i == self.dst_i {
self.last_line()
} else {
panic!("{} isn't an endpoint of {}", i, self.id);
}
}
pub fn dist_along_of_point(&self, pt: Pt2D) -> Option<Distance> {
self.lane_center_pts
.dist_along_of_point(pt)
.map(|(dist, _)| dist)View on GitHub (pinned to 0964f29315)