{"record":{"id":"c8b1424d87ea0cb8","repo":"a-b-street/abstreet","slug":"infinite-loop-starting-from-start","errorCode":null,"errorMessage":"Infinite loop starting from {start} ({})","messagePattern":"Infinite loop starting from (.+?) \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"blockfinding/src/lib.rs","lineNumber":106,"sourceCode":"                if next.road == current_road_side.road {\n                    if sorted_roads.len() != 2 {\n                        bail!(\"Looped back on the same road, but not at a dead-end\");\n                    }\n                }\n            }\n            roads.push(current_road_side);\n            current_road_side = next;\n            current_intersection = map\n                .get_r(current_road_side.road)\n                .other_endpt(current_intersection);\n\n            if current_road_side == start_road_side {\n                roads.push(start_road_side);\n                break;\n            }\n\n            if roads.len() > map.all_roads().len() {\n                bail!(\n                    \"Infinite loop starting from {start} ({})\",\n                    map.get_parent(start).orig_id\n                );\n            }\n        }\n        assert_eq!(roads[0], *roads.last().unwrap());\n        Ok(Perimeter {\n            roads,\n            interior: BTreeSet::new(),\n        })\n    }\n\n    /// This calculates all single block perimeters for the entire map. The resulting list does not\n    /// cover roads near the map boundary.\n    pub fn find_all_single_blocks(map: &Map) -> Vec<Perimeter> {\n        let skip = Perimeter::find_roads_to_skip_tracing(map);\n\n        let mut seen = HashSet::new();","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/blockfinding/src/lib.rs#L88-L124","documentation":"The perimeter walk exceeded one step per road in the whole map without returning to the start road side, so the trace must be looping forever. The library bails and reports the start lane and its parent road's original OSM ID to help locate the pathological geometry.","triggerScenarios":"single_block's loop visits more roads than map.all_roads().len() without current_road_side returning to start_road_side — a cycle in the road-side graph that never closes on the start side.","commonSituations":"Bug-prone map geometry such as figure-eight loop roads, one-way pairs the walker oscillates between, or maps corrupted by edits; also seen with unusual skip sets that break the expected clockwise ordering.","solutions":["Check the reported start road's geometry (orig_id) for loops or duplicate ways in the OSM source and fix them.","Adjust the `skip` set so the trace can't oscillate between the problematic roads.","Retry after regenerating the map with a newer map_model import, which may fix road-side sorting."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = Perimeter::single_block(map, start, &skip) {\n    if e.to_string().contains(\"Infinite loop\") {\n        // record start road orig_id for map QA; skip this seed\n        continue;\n    }\n    return Err(e);\n}","preventionTips":["Log the reported orig_id and audit that way's OSM geometry for loops.","Keep skip sets for oscillation-prone one-way pairs."],"tags":["infinite-loop","perimeter-tracing"],"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"}