apache/iceberg · error · java.lang.UnsupportedOperationException
Failed to read Variant %s of type %s as timestamp
Error message
Failed to read Variant %s of type %s as timestamp
What it means
timestampValue converts a Variant to TimestampData only for recognized timestamp variant types (with micros/nanos precision); any other Variant type throws this UnsupportedOperationException via errMsg(variant, "timestamp").
Source
Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/data/VariantRowDataWrapper.java:295
private static DecimalData decimalDataValue(Variant variant, DecimalType decimalType) {
return DecimalData.fromBigDecimal(
variant.getDecimal(), decimalType.getPrecision(), decimalType.getScale());
}
private static TimestampData timestampValue(Variant variant, int precision) {
return switch (variant.getType()) {
case TIMESTAMP -> TimestampData.fromLocalDateTime(variant.getDateTime());
case TIMESTAMP_LTZ -> TimestampData.fromInstant(variant.getInstant());
case BIGINT -> {
Preconditions.checkArgument(
precision >= MICROSECOND_PRECISION && precision <= NANOSECOND_PRECISION,
"Invalid precision: %s. Only micros and nanos precision are supported.",
precision);
yield precision > MICROSECOND_PRECISION
? nanoTimestampValue(variant.getLong())
: microTimestampValue(variant.getLong());
}
default -> throw new UnsupportedOperationException(errMsg(variant, "timestamp"));
};
}
private static TimestampData microTimestampValue(long micros) {
return TimestampData.fromEpochMillis(
Math.floorDiv(micros, 1000L), (int) Math.floorMod(micros, 1000L) * 1000);
}
private static TimestampData nanoTimestampValue(long nanos) {
return TimestampData.fromEpochMillis(
Math.floorDiv(nanos, 1_000_000L), (int) Math.floorMod(nanos, 1_000_000L));
}
private Variant field(int position) {
String fieldName = rowType.getFields().get(position).getName();
return variantData.getField(fieldName);
}
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure the writer stores a proper timestamp-typed Variant (not a raw long/string)
- Convert the value to a timestamp variant upstream before writing
- Use getLong and construct TimestampData manually if the column actually holds epoch values
Example fix
// before row.getTimestamp(7, 6); // variant holds epoch millis as LONG -> throws // after TimestampData ts = TimestampData.fromEpochMillis(row.getLong(7));
Defensive patterns
Strategy: try-catch
Validate before calling
if (variant.getType() != Variant.Type.TIMESTAMP_MICROS
&& variant.getType() != Variant.Type.TIMESTAMP_NANOS) { /* not a timestamp variant */ } Type guard
boolean isTimestampVariant(Variant v) {
return v.getType() == Variant.Type.TIMESTAMP_MICROS || v.getType() == Variant.Type.TIMESTAMP_NANOS;
} Try / catch
try { return row.getTimestamp(pos, precision); }
catch (UnsupportedOperationException e) { /* epoch long in column: construct TimestampData manually */ } Prevention
- Store timestamp-typed variants, never raw epoch longs or strings
- Keep writer and reader precision (micros/nanos) aligned
- Validate variant types after schema evolution
When it happens
Trigger: Calling getTimestamp on a VariantRowDataWrapper column holding a non-timestamp variant, or elementValue resolving a TIMESTAMP-typed field whose variant is e.g. a string or long without timestamp variant type.
Common situations: Writers storing epoch longs or ISO strings in variant columns while the Flink schema declares TIMESTAMP; table schema evolution from long to timestamp.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- errMsg(variant, "timestamp")
- Unknown type for long field. Type name: ${className}
- Unknown type for timestamp_ns: ${class}
- Unexpected object type for TIMESTAMP logical type. Received:
- Failed to read Variant %s of type %s as int
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/b3319b74cd8a00e8.
Report an issue: GitHub.