{"record":{"id":"50bd5d0d3b776c6d","repo":"databendlabs/databend","slug":"polygon-geometry-50bd5d","errorCode":null,"errorMessage":"polygon geometry","messagePattern":"polygon geometry","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/expression/src/geographic/overlay.rs","lineNumber":170,"sourceCode":"\n        if elements\n            .iter()\n            .all(|geo| matches!(geo, Geometry::LineString(_)))\n        {\n            let lines: Vec<LineString<f64>> = elements\n                .into_iter()\n                .map(|geo| geo.try_into().expect(\"linestring geometry\"))\n                .collect();\n            return Some(Geometry::MultiLineString(MultiLineString::from_iter(lines)));\n        }\n\n        if elements\n            .iter()\n            .all(|geo| matches!(geo, Geometry::Polygon(_)))\n        {\n            let polygons: Vec<Polygon<f64>> = elements\n                .into_iter()\n                .map(|geo| geo.try_into().expect(\"polygon geometry\"))\n                .collect();\n            return Some(Geometry::MultiPolygon(MultiPolygon::from_iter(polygons)));\n        }\n\n        Some(Geometry::GeometryCollection(GeometryCollection::from_iter(\n            elements,\n        )))\n    }\n\n    fn apply_union_iter<I>(&self, geos: I) -> Result<Option<Geometry<f64>>>\n    where I: IntoIterator<Item = Geometry<f64>> {\n        let mut merged = OverlayParts::default();\n        let mut has_input = false;\n\n        for geo in geos {\n            let parts = Self::prepare_operand(&geo)?;\n            Self::extend_parts(&mut merged, parts);\n            has_input = true;","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/expression/src/geographic/overlay.rs#L152-L188","documentation":"In geographic overlay's `build_geometry_from_elements`, when all elements are `Geometry::Polygon(_)`, each is converted with `try_into().expect(\"polygon geometry\")` to produce a MultiPolygon. The type guard should guarantee success, so this panic means the Polygon TryFrom impl failed on a guarded value — an internal invariant break or invalid polygon data generated during overlay.","triggerScenarios":"Overlay results composed entirely of polygons where the `TryFrom<Geometry> for Polygon<f64>` conversion returns Err — e.g. polygons with empty or self-invalid rings produced by the overlay algorithm.","commonSituations":"Overlaying complex/self-intersecting polygons producing degenerate results; geo crate version drift; floating-point precision issues corrupting rings.","solutions":["Validate overlay-produced polygons (non-empty valid exterior ring).","Check the geo crate TryFrom impl for the version in use.","Propagate conversion failure as `None` per the function's Option contract instead of panicking."],"exampleFix":"// before\n.map(|geo| geo.try_into().expect(\"polygon geometry\"))\n// after\n.map(|geo| geo.try_into().ok())\n.collect::<Option<Vec<_>>>()?;","handlingStrategy":"validation","validationCode":"// before overlay:\nlet valid = geoms.iter().all(|g| matches!(g, Geometry::Polygon(p) if !p.exterior().coords().is_empty()));","typeGuard":"fn has_valid_exterior(g: &Geometry) -> bool { matches!(g, Geometry::Polygon(p) if p.exterior().coords().count() >= 4) }","tryCatchPattern":"let result = std::panic::catch_unwind(|| overlay(geoms.clone()));","preventionTips":["Pre-validate polygon rings before overlay to avoid degenerate outputs.","Handle self-intersecting inputs with a validity check (e.g. geo's is_valid) first.","File a bug with the input geometries if this panic reproduces — the guard should prevent it."],"tags":["rust","geospatial","overlay"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}