apache/beam · error · UnsupportedOperationException

Unexpected logical type: {}

Error message

Unexpected logical type: {}

What it means

ApplyWatermarkColumn.getInstant converts a record field value into an Instant to use as the event watermark. It recognizes only a fixed set of logical types (timestamp-with-local-tz variants). When a different logicalType reaches the converter inside a recognized switch branch, it throws UnsupportedOperationException naming the unexpected logical type.

Source

Thrown at sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/cdc/ApplyWatermarkColumn.java:86

      return null;
    }
    switch (field.getType().getTypeName()) {
      case INT64:
        return Instant.ofEpochMilli(timeUnit.toMillis((Long) value));
      case DATETIME:
        return (Instant) value;
      case LOGICAL_TYPE:
        String logicalType =
            Preconditions.checkStateNotNull(field.getType().getLogicalType()).getIdentifier();
        if (logicalType.equals(SqlTypes.DATETIME.getIdentifier())) {
          return Instant.ofEpochMilli(
              MICROSECONDS.toMillis(DateTimeUtil.microsFromTimestamp((LocalDateTime) value)));
        } else if (logicalType.equals(SqlTypes.TIMESTAMP.getIdentifier())
            || logicalType.equals(org.apache.beam.sdk.schemas.logicaltypes.Timestamp.IDENTIFIER)) {
          return Instant.ofEpochMilli(
              MICROSECONDS.toMillis(DateTimeUtil.microsFromInstant((java.time.Instant) value)));
        } else {
          throw new UnsupportedOperationException("Unexpected logical type: " + logicalType);
        }
      default:
        throw new UnsupportedOperationException("Unexpected Beam type: " + field.getType());
    }
  }

  @Override
  public Duration getAllowedTimestampSkew() {
    // Generous skew to cover backfill of historical data and late-arriving CDC patterns.
    return Duration.standardDays(365);
  }
}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Ensure the watermark column's Beam logical type is SqlTypes.TIMESTAMP or beam Timestamp logical type; convert the field's schema accordingly when building the output schema.
  2. Pre-convert DATE/TIME or custom logical types to a supported timestamp logical type in an earlier PTransform.
  3. Update or patch ApplyWatermarkColumn to handle the needed logical type and re-check with your Beam version.
  4. Log/print field.getType() and its logical type identifier before applying the watermark transform to confirm what is actually arriving.

Example fix

// before
Schema.Field watermarkField = schema.getField("event_time"); // DATE logical type
// after
Schema.Field watermarkField =
    Schema.Field.of("event_time", Schema.FieldType.logicalType(SqlTypes.TIMESTAMP));
Defensive patterns

Strategy: type-guard

Validate before calling

Schema.LogicalTypeSupplier lt = schema.getField(col).getType().getLogicalType();
if (lt == null || !(isSqlTimestamp(lt) || isBeamTimestamp(lt))) {
  throw new IllegalArgumentException("Watermark column must use a timestamp logical type");
}

Type guard

static boolean isSupportedTimestamp(FieldType t) {
  return t.getLogicalType() != null && (
      SqlTypes.TIMESTAMP.getIdentifier().equals(t.getLogicalType().getIdentifier()) ||
      org.apache.beam.sdk.schemas.logicaltypes.Timestamp.IDENTIFIER.equals(t.getLogicalType().getIdentifier()));
}

Try / catch

try {
  records.apply(ApplyWatermarkColumn.create(col));
} catch (UnsupportedOperationException e) {
  if (e.getMessage().startsWith("Unexpected logical type")) {
    throw new IllegalArgumentException("Coerce column to a supported timestamp logical type first");
  }
  throw e;
}

Prevention

When it happens

Trigger: A Beam schema field whose logicalType identifier is neither SqlTypes.TIMESTAMP.getIdentifier() nor org.apache.beam.sdk.schemas.logicaltypes.Timestamp.IDENTIFIER is passed to getInstant, e.g. a DATE, TIME, or custom logical type used as the watermark column.

Common situations: Configuring the CDC/watermark column as a DATE or naive TIMESTAMP (LocalDateTime without tz) variant not in the accepted set, or schema evolution changing the field's logical type; using a Beam logical type from a different SDK version whose identifier differs.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/516622ff9eecb15d. Report an issue: GitHub.