{"record":{"id":"ff31fb08ff9473ce","repo":"a-b-street/abstreet","slug":"multipolygon-was-unexpectedly-empty","errorCode":null,"errorMessage":"multipolygon was unexpectedly empty","messagePattern":"multipolygon was unexpectedly empty","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"popdat/src/import_census.rs","lineNumber":60,"sourceCode":"            if !props.contains_key(\"population\") {\n                warn!(\"skipping feature with missing population\");\n                continue;\n            }\n            let population: usize = props[\"population\"].parse()?;\n            let geometry = match feature.geometry() {\n                Some(g) => g,\n                None => {\n                    warn!(\"skipping feature with missing geometry\");\n                    continue;\n                }\n            };\n            let mut geo = GeoWriter::new();\n            geometry.process(&mut geo, flatgeobuf::GeometryType::MultiPolygon)?;\n            if let Some(geo::Geometry::MultiPolygon(multi_poly)) = geo.take_geometry() {\n                let geo_polygon = multi_poly\n                    .0\n                    .first()\n                    .ok_or_else(|| anyhow!(\"multipolygon was unexpectedly empty\"))?;\n                if multi_poly.0.len() > 1 {\n                    warn!(\n                        \"dropping {} extra polygons from census area: {:?}\",\n                        multi_poly.0.len() - 1,\n                        props\n                    );\n                }\n\n                if !geo_polygon.intersects(&geo_map_area) {\n                    debug!(\n                        \"skipping polygon outside of map area. polygon: {:?}, map_area: {:?}\",\n                        geo_polygon, geo_map_area\n                    );\n                    continue;\n                }\n\n                let mut polygon = geo_polygon.clone();\n                polygon.map_coords_in_place(|c| geom::LonLat::new(c.x, c.y).to_pt(bounds).into());","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/popdat/src/import_census.rs#L42-L78","documentation":"While iterating census area features from the flatgeobuf file, each MultiPolygon geometry is converted and only its first polygon is kept. If the MultiPolygon has zero polygons (an empty geometry), .first() is None and this error is thrown. It signals a malformed/degenerate census feature rather than a caller mistake.","triggerScenarios":"fetch_all_for_map reads a feature whose decoded geometry yields geo::Geometry::MultiPolygon with an empty Vec — an empty census area polygon in population_areas.fgb, or a failed/partial geometry decode by GeoWriter.","commonSituations":"Upstream changes to the census source producing empty polygons for some regions; querying the FGB at a bbox edge that clips features to nothing; stale or corrupted cached fgb data.","solutions":["Skip empty MultiPolygon features with a warning instead of failing the whole import","Regenerate/re-download population_areas.fgb from the source","Validate geometry non-emptiness in the import handbook pipeline before publishing the fgb"],"exampleFix":"// before\nlet geo_polygon = multi_poly.0.first().ok_or_else(|| anyhow!(\"multipolygon was unexpectedly empty\"))?;\n// after\nlet geo_polygon = match multi_poly.0.first() {\n    Some(p) => p,\n    None => {\n        warn!(\"census area {:?} has an empty multipolygon; skipping\", props);\n        continue;\n    }\n};","handlingStrategy":"fallback","validationCode":"// treat empty multipolygons as skippable at the decode site\nif let geo::Geometry::MultiPolygon(mp) = &geom_result {\n    if mp.0.is_empty() { /* skip feature */ }\n}","typeGuard":"fn non_empty_multipolygon(g: &geo::Geometry<f64>) -> Option<&geo::MultiPolygon<f64>> {\n    match g { geo::Geometry::MultiPolygon(mp) if !mp.0.is_empty() => Some(mp), _ => None }\n}","tryCatchPattern":"match fetch_all_for_map(map).await { Err(e) if e.to_string().contains(\"unexpectedly empty\") => warn!(\"some census features were empty; results partial\"), r => r }","preventionTips":["Re-download the fgb if empty features appear","Clip queries with a slightly padded bbox to avoid zero-area clips","Log offending feature properties for upstream fixes","Prefer skipping over failing the whole population import"],"tags":["gis","census","import","flatgeobuf"],"backgroundTag":"unexpected-response-shape","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"}