apache/iceberg · error · java.lang.UnsupportedOperationException

Failed to read Variant %s of type %s as double

Error message

Failed to read Variant %s of type %s as double

What it means

Thrown by VariantRowDataWrapper.doubleValue: a double was requested from a variant whose primitive type is neither FLOAT nor DOUBLE (the handled cases). The message includes the variant value and its type; the consuming Flink job's expected row type disagrees with the variant's stored type.

Source

Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/data/VariantRowDataWrapper.java:273

      default -> throw new UnsupportedOperationException(errMsg(variant, "int"));
    };
  }

  private static long longValue(Variant variant) {
    return switch (variant.getType()) {
      case TINYINT -> variant.getByte();
      case SMALLINT -> variant.getShort();
      case INT -> variant.getInt();
      case BIGINT -> variant.getLong();
      default -> throw new UnsupportedOperationException(errMsg(variant, "long"));
    };
  }

  private static double doubleValue(Variant variant) {
    return switch (variant.getType()) {
      case FLOAT -> variant.getFloat();
      case DOUBLE -> variant.getDouble();
      default -> throw new UnsupportedOperationException(errMsg(variant, "double"));
    };
  }

  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

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure the variant's physical type is FLOAT or DOUBLE when written
  2. Align the RowType field to DECIMAL and read via getDecimal if variants are decimals
  3. Convert the value upstream to double before writing

Example fix

// before
row.getDouble(5); // variant is DECIMAL -> throws
// after
DecimalData d = row.getDecimal(5, precision, scale);
Defensive patterns

Strategy: try-catch

Validate before calling

if (variant.getType() != Variant.Type.FLOAT
    && variant.getType() != Variant.Type.DOUBLE) { /* use decimal/other accessor */ }

Type guard

boolean isFloatingPoint(Variant v) {
  return v.getType() == Variant.Type.FLOAT || v.getType() == Variant.Type.DOUBLE;
}

Try / catch

try { return row.getDouble(pos); }
catch (UnsupportedOperationException e) { /* fall back to getDecimal and convert */ }

Prevention

When it happens

Trigger: Calling getDouble on a VariantRowDataWrapper column whose variant is, e.g., a string or decimal rather than a float/double, or elementValue with a DOUBLE-typed field holding another variant type.

Common situations: Writers producing decimal variants for double columns; schema drift where a double column now stores numeric variants of other widths.

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/2887fcd3900e6a25. Report an issue: GitHub.