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
- 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.
- Pre-convert DATE/TIME or custom logical types to a supported timestamp logical type in an earlier PTransform.
- Update or patch ApplyWatermarkColumn to handle the needed logical type and re-check with your Beam version.
- 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
- Declare watermark columns with SqlTypes.TIMESTAMP logical types.
- Coerce DATE/TIME/custom logical types upstream before the watermark transform.
- Re-verify schema after any upstream schema evolution.
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
- Unexpected Beam type: {}
- Logical types don't match and cannot be merged: +identifier1
- @WatermarkEstimatorState parameters are not supported.
- Unknown DateTime type ${logicalId}
- Unknown logical type
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/516622ff9eecb15d.
Report an issue: GitHub.