a-b-street/abstreet · error
doesn't connect to
Error message
{} doesn't connect to {} What it means
After rebuilding a stop sign for a permanent edit, each edited road id must exist in the new ControlStopSign's road set. If a road referenced by the edit is not adjacent to the intersection anymore, the edit cannot be applied and the library bails naming the intersection and the road id.
Solutions
- Remove the stale road entry from the stop-sign edit (verify the road id exists on that intersection in the current map).
- Recreate the stop-sign edit on the current map version via the UI or edits tooling.
- If the road id was renumbered by regeneration, remap the edit with the map's id-mapping before applying.
Example fix
// before (edit references road that no longer touches the intersection)
bail!("{} doesn't connect to {}", i, r);
// after (skip/repair stale roads before applying)
let ss = ControlStopSign::new(map, i);
for (r, stop) in translated_must_stop {
if ss.roads.contains_key(&r) {
ss.roads.get_mut(&r).unwrap().must_stop = stop;
}
} Defensive patterns
Strategy: validation
Validate before calling
for (r, _) in &translated_must_stop {
assert!(map.get_i(i).roads.contains(r), "road {:?} no longer touches {:?}", r, i);
} Try / catch
match with_permanent(...) {
Err(e) if e.to_string().contains("doesn't connect to") => {
// drop the stale stop-sign edit and re-record it
}
other => other?,
} Prevention
- Never hand-edit road ids in edits files
- Re-record stop-sign edits after any map regeneration
- Diff permanent edits for road deletions/merges before layering stop-sign edits
When it happens
Trigger: with_permanent applying EditIntersectionControl::StopSign where translated_must_stop contains a RoadID not present in ss.roads — typically because the permanent edits deleted, merged, or renumbered roads touching that intersection.
Common situations: Applying an old edits.json to a regenerated map; layering edits on top of permanent edits that changed road topology; sharing edits between slightly different map builds.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Stop sign has roads now, but from edits
- must_get_sidewalk broken by
- doesn't contain both and
- Breaking changes happened to map edits between v12 and v13…
- didn't map to exactly 1 crossing turn
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/6d66ff2654070cd5.
Report an issue: GitHub.
Appendix: source
Thrown at map_model/src/edits/perma.rs:280
let mut translated_must_stop = BTreeMap::new();
for (r, stop) in must_stop {
translated_must_stop.insert(map.find_r_by_osm_id(r)?, stop);
}
// Make sure the roads exactly match up
let mut ss = ControlStopSign::new(map, i);
if translated_must_stop.len() != ss.roads.len() {
bail!(
"Stop sign has {} roads now, but {} from edits",
ss.roads.len(),
translated_must_stop.len()
);
}
for (r, stop) in translated_must_stop {
if let Some(road) = ss.roads.get_mut(&r) {
road.must_stop = stop;
} else {
bail!("{} doesn't connect to {}", i, r);
}
}
EditIntersectionControl::StopSign(ss)
}
PermanentEditIntersectionControl::TrafficSignal(ts) => {
EditIntersectionControl::TrafficSignal(ts)
}
PermanentEditIntersectionControl::Closed => EditIntersectionControl::Closed,
};
let mut crosswalks = BTreeMap::new();
for (id, turn_type) in self.crosswalks {
let movement = MovementID::from_permanent(id, map)?;
// Find all TurnIDs that map to this MovementID
let mut turn_ids = Vec::new();
for turn in &map.get_i(i).turns {
if turn.id.to_movement(map) == movement {View on GitHub (pinned to 0964f29315)