{"record":{"id":"61d8545ad115acf8","repo":"a-b-street/abstreet","slug":"two-perimeters-had-every-road-in-common","errorCode":null,"errorMessage":"Two perimeters had every road in common: {:?}","messagePattern":"Two perimeters had every road in common: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"blockfinding/src/lib.rs","lineNumber":309,"sourceCode":"                    );\n                }\n            }\n\n            // Very straightforward snipping now\n            for _ in 0..common.len() {\n                self.roads.pop().unwrap();\n                other.roads.pop().unwrap();\n            }\n\n            // This order assumes everything is clockwise to start with.\n            self.roads.append(&mut other.roads);\n\n            // TODO This case was introduced with find_roads_to_skip_tracing. Not sure why.\n            if self.roads.is_empty() {\n                if debug_failures {\n                    warn!(\"Two perimeters had every road in common: {:?}\", common);\n                }\n                bail!(\"Two perimeters had every road in common: {:?}\", common);\n            }\n\n            self.interior.extend(common);\n            self.interior.append(&mut other.interior);\n\n            // Restore the first=last invariant\n            self.restore_invariant();\n\n            // Make sure we didn't wind up with any internal dead-ends\n            self.collapse_deadends();\n\n            if let Err(err) = self.check_continuity(map) {\n                debug!(\n                    \"A merged perimeter couldn't be blockified: {}. {:?}\",\n                    err, self\n                );\n                bail!(\n                    \"A merged perimeter couldn't be blockified: {}. {:?}\",","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/blockfinding/src/lib.rs#L291-L327","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-run blockfinding on the latest map import; this is a known internal edge case that map/preprocessing fixes may eliminate.","Check the map for duplicate or degenerate road rings around the block in question.","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.","Filter or log the failing block candidate and continue with other blocks rather than treating it as fatal."],"exampleFix":"// before\nbail!(\"Two perimeters had every road in common: {:?}\", common);\n// after\nif common.len() == 1 {\n    // degenerate two-road ring: skip merge instead of failing\n    return Ok(None);\n}\nbail!(\"Two perimeters had every road in common: {:?}\", common);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match perimeter1.try_to_merge(perimeter2, map, ...) {\n    Err(e) if e.to_string().contains(\"every road in common\") => {\n        warn!(\"skipping degenerate block: {}\", e);\n    }\n    other => other?,\n}","preventionTips":["Regenerate blocks on freshly imported maps","Deduplicate candidate perimeters before merging","Treat this failure as skip-this-block, not fatal"],"tags":["geometry","blocks","internal-invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}