apache/iceberg · error · UnsupportedOperationException

Unknown transform class %s

Error message

Unknown transform class %s

What it means

PartitionSpecVisitor.visit() throws this after exhausting its instanceof dispatch over all known transform classes (Identity, Bucket, Truncate, Years/Months/Days/Hours, VoidTransform, UnknownTransform and the legacy Dates/Timestamps singletons). Hitting it means a PartitionField's transform is an object of a class the visitor dispatcher does not recognize at all — distinct from the per-transform default hooks, this is a dispatch-level failure inside Iceberg itself.

Source

Thrown at api/src/main/java/org/apache/iceberg/transforms/PartitionSpecVisitor.java:149

        || transform == Timestamps.NANOS_TO_MONTH
        || transform instanceof Months) {
      return visitor.month(field.fieldId(), sourceName, field.sourceId());
    } else if (transform == Dates.DAY
        || transform == Timestamps.MICROS_TO_DAY
        || transform == Timestamps.NANOS_TO_DAY
        || transform instanceof Days) {
      return visitor.day(field.fieldId(), sourceName, field.sourceId());
    } else if (transform == Timestamps.MICROS_TO_HOUR
        || transform == Timestamps.NANOS_TO_HOUR
        || transform instanceof Hours) {
      return visitor.hour(field.fieldId(), sourceName, field.sourceId());
    } else if (transform instanceof VoidTransform) {
      return visitor.alwaysNull(field.fieldId(), sourceName, field.sourceId());
    } else if (transform instanceof UnknownTransform) {
      return visitor.unknown(field.fieldId(), sourceName, field.sourceId(), transform.toString());
    }

    throw new UnsupportedOperationException(
        String.format("Unknown transform class %s", field.transform().getClass().getName()));
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure all Iceberg modules use the same version — check the classpath for duplicate/conflicting iceberg-api jars (mvn dependency:tree)
  2. If you ship a custom Transform subclass, it cannot be dispatched here; convert the spec field to a standard transform or extend the visitor dispatch path upstream
  3. Reproduce with field.transform().getClass().getName() from the message to identify the offending class and its jar

Example fix

// before
Transform myTransform = new MyCustomTransform(); // not dispatched by visit()
// after
Transforms.identity() // or another standard transform (bucket/truncate/year/...) known to visit()
Defensive patterns

Strategy: validation

Validate before calling

// Detect non-standard transform classes before dispatch:
Set<String> known = Set.of("Identity", "Bucket", "Truncate", "Years", "Months", "Days",
    "Hours", "VoidTransform", "UnknownTransform");
for (PartitionField f : spec.fields()) {
  String cls = f.transform().getClass().getSimpleName();
  if (!known.contains(cls)) throw new IllegalStateException("Non-standard transform: " + cls);
}

Type guard

if (!(field.transform() instanceof Identity || field.transform() instanceof Bucket
    || field.transform() instanceof Truncate || field.transform() instanceof VoidTransform
    || field.transform() instanceof UnknownTransform
    || field.transform() instanceof Years || field.transform() instanceof Months
    || field.transform() instanceof Days || field.transform() instanceof Hours)) {
  throw new IllegalStateException("Unsupported transform class: " + field.transform().getClass());
}

Try / catch

try {
  PartitionSpecVisitor.visit(spec, visitor);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().startsWith("Unknown transform class")) {
    throw new IllegalStateException("Mixed Iceberg versions or custom transform on classpath", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: A PartitionField carries a Transform instance outside the known set — typically a user-defined Transform subclass implementation, or a class from a different/patched Iceberg version placed on the classpath, passed to PartitionSpecVisitor.visit(schema, field, visitor).

Common situations: Custom Transform implementations registered via custom serialization on the writer side; mixed Iceberg jar versions (shaded vs non-shaded, vendor forks) so the same logical transform fails instanceof checks; third-party catalogs injecting custom transform objects into specs.

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 apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/8bc4f480b18d37da. Report an issue: GitHub.