apache/iceberg · error · java.lang.UnsupportedOperationException

Cannot convert Spark geometry with mixed SRID to Iceberg

Error message

Cannot convert Spark geometry with mixed SRID to Iceberg

What it means

SparkTypeToType converts Spark types to Iceberg types. A Spark GeometryType with mixed SRID (coordinates referencing different spatial reference systems) cannot be represented by a single Iceberg GeometryType, which carries one CRS. Conversion throws this UnsupportedOperationException rather than silently dropping SRID information.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/SparkTypeToType.java:173

    } else if (atomic instanceof DateType) {
      return Types.DateType.get();

    } else if (atomic instanceof TimestampType) {
      return Types.TimestampType.withZone();

    } else if (atomic instanceof TimestampNTZType) {
      return Types.TimestampType.withoutZone();

    } else if (atomic instanceof DecimalType) {
      return Types.DecimalType.of(
          ((DecimalType) atomic).precision(), ((DecimalType) atomic).scale());
    } else if (atomic instanceof BinaryType) {
      return Types.BinaryType.get();
    } else if (atomic instanceof GeometryType) {
      GeometryType geometry = (GeometryType) atomic;
      if (geometry.isMixedSrid()) {
        throw new UnsupportedOperationException(
            "Cannot convert Spark geometry with mixed SRID to Iceberg");
      }
      return Types.GeometryType.of(geometry.crs());
    } else if (atomic instanceof GeographyType) {
      GeographyType geography = (GeographyType) atomic;
      if (geography.isMixedSrid()) {
        throw new UnsupportedOperationException(
            "Cannot convert Spark geography with mixed SRID to Iceberg");
      }
      return Types.GeographyType.of(geography.crs(), convertAlgorithm(geography.algorithm()));
    } else if (atomic instanceof NullType) {
      return Types.UnknownType.get();
    }

    throw new UnsupportedOperationException("Not a supported type: " + atomic.catalogString());
  }

  // Translates Spark's edge-interpolation algorithm to Iceberg's, mirroring

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Normalize the geometry column to a single SRID before handing the schema to Iceberg (ST_Transform / reproject each geometry)
  2. Split mixed-SRID data into separate columns per SRID
  3. Store geometries as binary if single-SRID enforcement can't be met (with SRID managed by convention)
  4. Reject or quarantine offending rows upstream so the column is single-SRID

Example fix

// before
df.select(functions.expr("st_setsrid(geom, 4326)")) // mixed SRIDs remain in some rows
// after
df = df.withColumn("geom", functions.expr("st_transform(geom, 'EPSG:4326')")); // single SRID everywhere
Defensive patterns

Strategy: validation

Validate before calling

if (sparkGeomType.isMixedSrid()) {
  throw new IllegalStateException("Normalize geometry SRID before Iceberg conversion");
}

Type guard

if (dt instanceof org.apache.spark.sql.types.GeometryType g && g.isMixedSrid()) {
  return false; // not convertible until reprojected
}

Try / catch

try {
  icebergType = converter.convert(sparkSchema);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("mixed SRID")) {
    // reproject to one SRID and retry
  }
}

Prevention

When it happens

Trigger: Reading or writing Spark DataFrames whose schema contains a geometry column flagged as mixed-SRID while Iceberg converts the schema (e.g. SparkScan/SchemaConverter paths).

Common situations: Ingesting heterogeneous spatial data from multiple sources into one geometry column; lossy SRID assignment upstream in Spark; spatial ETL mixing WGS84 and projected coordinates in a single column.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/bdec35966ec8e31e. Report an issue: GitHub.