databendlabs/databend · error

polygon geometry

Error message

polygon geometry

What it means

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.

Solutions

  1. Validate overlay-produced polygons (non-empty valid exterior ring).
  2. Check the geo crate TryFrom impl for the version in use.
  3. Propagate conversion failure as `None` per the function's Option contract instead of panicking.

Example fix

// before
.map(|geo| geo.try_into().expect("polygon geometry"))
// after
.map(|geo| geo.try_into().ok())
.collect::<Option<Vec<_>>>()?;
Defensive patterns

Strategy: validation

Validate before calling

// before overlay:
let valid = geoms.iter().all(|g| matches!(g, Geometry::Polygon(p) if !p.exterior().coords().is_empty()));

Type guard

fn has_valid_exterior(g: &Geometry) -> bool { matches!(g, Geometry::Polygon(p) if p.exterior().coords().count() >= 4) }

Try / catch

let result = std::panic::catch_unwind(|| overlay(geoms.clone()));

Prevention

When it happens

Trigger: 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.

Common situations: Overlaying complex/self-intersecting polygons producing degenerate results; geo crate version drift; floating-point precision issues corrupting rings.

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 databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/50bd5d0d3b776c6d. Report an issue: GitHub.

Appendix: source

Thrown at src/query/expression/src/geographic/overlay.rs:170

        if elements
            .iter()
            .all(|geo| matches!(geo, Geometry::LineString(_)))
        {
            let lines: Vec<LineString<f64>> = elements
                .into_iter()
                .map(|geo| geo.try_into().expect("linestring geometry"))
                .collect();
            return Some(Geometry::MultiLineString(MultiLineString::from_iter(lines)));
        }

        if elements
            .iter()
            .all(|geo| matches!(geo, Geometry::Polygon(_)))
        {
            let polygons: Vec<Polygon<f64>> = elements
                .into_iter()
                .map(|geo| geo.try_into().expect("polygon geometry"))
                .collect();
            return Some(Geometry::MultiPolygon(MultiPolygon::from_iter(polygons)));
        }

        Some(Geometry::GeometryCollection(GeometryCollection::from_iter(
            elements,
        )))
    }

    fn apply_union_iter<I>(&self, geos: I) -> Result<Option<Geometry<f64>>>
    where I: IntoIterator<Item = Geometry<f64>> {
        let mut merged = OverlayParts::default();
        let mut has_input = false;

        for geo in geos {
            let parts = Self::prepare_operand(&geo)?;
            Self::extend_parts(&mut merged, parts);
            has_input = true;

View on GitHub (pinned to 288d84d76e)