apache/iceberg · error · UnsupportedOperationException

errMsg(variant, "timestamp")

Error message

errMsg(variant, "timestamp")

What it means

timestampValue converts a Variant to a Flink TimestampData only when the variant holds a timestamp with micros or nanos precision; any other variant type (or precision) throws UnsupportedOperationException with errMsg(variant, "timestamp"). The switch also validates precision, rejecting precisions other than micros/nanos with "Invalid precision" beforehand.

Source

Thrown at flink/v2.2/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

  1. Ensure the writer stores timestamps using the variant timestamp type (micros or nanos).
  2. Read long variants via getLong and convert to TimestampData manually if that is the actual encoding.
  3. Align the Flink field type with the variant's stored type.

Example fix

// before
TimestampData ts = wrapper.getTimestamp(pos, 6); // variant is epoch-millis long
// after
long millis = wrapper.getLong(pos);
TimestampData ts = TimestampData.fromEpochMillis(millis);
Defensive patterns

Strategy: type-guard

Validate before calling

if (variant.getType() == Variant.Type.TIMESTAMP || variant.getType() == Variant.Type.TIMESTAMP_NANOS) { /* safe to getTimestamp */ }

Type guard

boolean isTimestampVariant(Variant v) { return v.getType() == Variant.Type.TIMESTAMP || v.getType() == Variant.Type.TIMESTAMP_NANOS; }

Try / catch

try { TimestampData ts = wrapper.getTimestamp(pos, 6); } catch (UnsupportedOperationException e) { /* convert from long/string variant manually */ }

Prevention

When it happens

Trigger: Calling getTimestamp(pos, precision) or elementValue where the Variant is not a timestamp type — e.g. a STRING or LONG variant read through a TIMESTAMP Flink field.

Common situations: Variant timestamps stored as strings/epoch longs rather than the variant timestamp type; version mismatch where the writer encodes timestamps differently; reading a date-only variant as timestamp.

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