apache/iceberg · error · ConnectException

Cannot convert time

Error message

Cannot convert time: ${value}

What it means

RecordConverter.convertTimeValue throws this ConnectException when a value mapped to an Iceberg Time column cannot be interpreted as a time. Accepted inputs are Numbers (millis since midnight), Strings (parsed), LocalTime, and java.util.Date; anything else fails.

Solutions

  1. Send the time as epoch millis since midnight (int32) with the Time logical type, or as a parseable string like "10:30:00"
  2. Add a TimestampConverter SMT to normalize to Time before the sink
  3. Fix the producer to emit a scalar temporal value instead of a nested object
  4. If the value is truly a timestamp, retarget the Iceberg column to timestamptz instead of time

Example fix

// before
producer value: {"hour":10,"minute":0} // object -> cannot convert time
// after
producer value: 36000000 // millis since midnight, Time logical type
Defensive patterns

Strategy: validation

Validate before calling

Object v = record.value().get("timeField");
if (!(v instanceof Number || v instanceof LocalTime || v instanceof java.util.Date || v instanceof String)) {
  throw new IllegalStateException("Time field bad type: " + (v == null ? "null" : v.getClass()));
}

Type guard

static boolean isTimeCompatible(Object v) {
  return v == null || v instanceof Number || v instanceof LocalTime
      || v instanceof java.util.Date || v instanceof String;
}

Try / catch

try {
  converter.convertValue(value, Types.TimeType.get());
} catch (ConnectException e) {
  log.error("Time conversion failed: " + e.getMessage(), e);
  // route to DLQ or coerce to millis-since-midnight number
}

Prevention

When it happens

Trigger: A Time field receives a struct/map/boolean value; or convertValue/ts passes an unparseable or non-temporal object to convertTimeValue.

Common situations: Kafka message contains a JSON object like {"hour":10,"minute":30} where the table expects time; producer sends epoch millis as a nested payload; schema registry logical type changed from Time to something else.

Related errors


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

Appendix: source

Thrown at kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordConverter.java:568

      return DateTimeUtil.dateFromDays(days);
    }
    throw new ConnectException("Cannot convert date: " + value);
  }

  @SuppressWarnings("JavaUtilDate")
  protected LocalTime convertTimeValue(Object value) {
    if (value instanceof Number) {
      long millis = ((Number) value).longValue();
      return DateTimeUtil.timeFromMicros(millis * 1000);
    } else if (value instanceof String) {
      return LocalTime.parse((String) value);
    } else if (value instanceof LocalTime) {
      return (LocalTime) value;
    } else if (value instanceof Date) {
      long millis = ((Date) value).getTime();
      return DateTimeUtil.timeFromMicros(millis * 1000);
    }
    throw new ConnectException("Cannot convert time: " + value);
  }

  protected Temporal convertTimestampValue(Object value, TimestampType type) {
    if (type.shouldAdjustToUTC()) {
      return convertOffsetDateTime(value);
    }
    return convertLocalDateTime(value);
  }

  protected Variant convertVariantValue(Object value) {
    if (value instanceof Variant variant) {
      return variant;
    }

    List<String> sortedFieldNames =
        collectFieldNames(value).stream().sorted().collect(Collectors.toList());
    VariantMetadata metadata = Variants.metadata(sortedFieldNames);
    return Variant.of(metadata, objectToVariantValue(value, metadata, null));

View on GitHub (pinned to 86d9c8fc54)