a-b-street/abstreet · warning

Two perimeters had every road in common

Error message

Two perimeters had every road in common: {:?}

What it means

In blockfinding, when merging two perimeters into one block, the merge algorithm found that both perimeters consisted of exactly the same set of roads, leaving an empty road list for the merged perimeter. This signals an internal degenerate case introduced by find_roads_to_skip_tracing; the library logs a warning (in debug mode) and aborts the merge rather than produce an invalid empty block.

Solutions

  1. Re-run blockfinding on the latest map import; this is a known internal edge case that map/preprocessing fixes may eliminate.
  2. Check the map for duplicate or degenerate road rings around the block in question.
  3. If you maintain this code, extend the merge logic (find_roads_to_skip_tracing) so the common-roads case resolves to a single perimeter instead of an empty one.
  4. Filter or log the failing block candidate and continue with other blocks rather than treating it as fatal.

Example fix

// before
bail!("Two perimeters had every road in common: {:?}", common);
// after
if common.len() == 1 {
    // degenerate two-road ring: skip merge instead of failing
    return Ok(None);
}
bail!("Two perimeters had every road in common: {:?}", common);
Defensive patterns

Strategy: try-catch

Try / catch

match perimeter1.try_to_merge(perimeter2, map, ...) {
    Err(e) if e.to_string().contains("every road in common") => {
        warn!("skipping degenerate block: {}", e);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling Perimeter::try_to_merge (via block generation) when two candidate perimeters have identical road sets, so self.roads becomes empty after moving all common roads into the interior.

Common situations: Map data with duplicate ring roads or overlapping perimeters; running the blockfinder over areas with cul-de-sacs or dual-carriageway loops that produce two perimeters covering the same roads.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at blockfinding/src/lib.rs:309

                    );
                }
            }

            // Very straightforward snipping now
            for _ in 0..common.len() {
                self.roads.pop().unwrap();
                other.roads.pop().unwrap();
            }

            // This order assumes everything is clockwise to start with.
            self.roads.append(&mut other.roads);

            // TODO This case was introduced with find_roads_to_skip_tracing. Not sure why.
            if self.roads.is_empty() {
                if debug_failures {
                    warn!("Two perimeters had every road in common: {:?}", common);
                }
                bail!("Two perimeters had every road in common: {:?}", common);
            }

            self.interior.extend(common);
            self.interior.append(&mut other.interior);

            // Restore the first=last invariant
            self.restore_invariant();

            // Make sure we didn't wind up with any internal dead-ends
            self.collapse_deadends();

            if let Err(err) = self.check_continuity(map) {
                debug!(
                    "A merged perimeter couldn't be blockified: {}. {:?}",
                    err, self
                );
                bail!(
                    "A merged perimeter couldn't be blockified: {}. {:?}",

View on GitHub (pinned to 0964f29315)