apache/iceberg · error · IllegalArgumentException
Cannot convert java.util.Date to variant without a…
Error message
Cannot convert java.util.Date to variant without a recognized logical type schema (expected Timestamp, Time, or Date but got: ${logicalName}) What it means
temporalObjectToVariantValue throws this IllegalArgumentException when a java.util.Date is converted to a Variant but the Connect schema lacks a recognized logical type. Date is ambiguous without logical type info (Timestamp, Time, or Date); otherwise the converter cannot know whether to emit a variant timestamp, time, or date value.
Solutions
- Attach Timestamp/Time/Date logical types via Timestamp.builder()/Time.builder()/Date.builder() when building the Connect schema
- Convert java.util.Date to java.time types (Instant, LocalTime, LocalDate) before the sink so no logical schema is needed
- Use TimestampConverter SMT to add the proper logical type
- Avoid schemaless records for variant fields containing temporal values
Example fix
// before Schema schema = SchemaBuilder.int64().build(); // no logical type // after Schema schema = Timestamp.builder().schema(SchemaBuilder.int64().build()).build();
Defensive patterns
Strategy: validation
Validate before calling
if (value instanceof java.util.Date) {
String logical = schema != null && schema.name() != null ? schema.name() : null;
boolean ok = org.apache.kafka.connect.data.Timestamp.LOGICAL_NAME.equals(logical)
|| org.apache.kafka.connect.data.Time.LOGICAL_NAME.equals(logical)
|| org.apache.kafka.connect.data.Date.LOGICAL_NAME.equals(logical);
if (!ok) throw new IllegalStateException("java.util.Date needs Timestamp/Time/Date logical schema, got: " + logical);
} Type guard
static boolean dateHasLogicalSchema(org.apache.kafka.connect.data.Schema s) {
if (s == null || s.name() == null) return false;
return Timestamp.LOGICAL_NAME.equals(s.name())
|| Time.LOGICAL_NAME.equals(s.name())
|| Date.LOGICAL_NAME.equals(s.name());
} Try / catch
try {
converter.convertValue(dateValue, variantType);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("recognized logical type schema")) {
log.error("Attach Timestamp/Time/Date logical schema or convert to java.time first", e);
// fallback: convert to Instant before sinking
}
} Prevention
- Never send java.util.Date in schemaless mode to Variant columns
- Always wrap temporal Connect fields with the proper logical-type builder
- Prefer java.time types (Instant, LocalDate, LocalTime) end to end
- Keep SMTs from stripping schema names/logical types
When it happens
Trigger: A java.util.Date value reaches variant conversion with schema null, a plain (non-logical) schema, or a logical type other than org.apache.kafka.connect.data.{Timestamp,Time,Date}.
Common situations: Schemaless mode (no schema attached to the record) delivering java.util.Date values; a custom logical type name from another converter; schema stripped by an SMT before the sink.
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
- Cannot convert map to variant: keys must be non-null…
- Cannot convert Number to variant (unknown type)
- Cannot convert to variant
- Unsupported shredded value type
- An error occurred closing catalog instance, ignoring...
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/85a76a538e9fbb71.
Report an issue: GitHub.
Appendix: source
Thrown at kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordConverter.java:764
if (value instanceof LocalTime localTime) {
return Variants.ofTime(DateTimeUtil.microsFromTime(localTime));
}
if (value instanceof Date date) {
String logicalName = schema != null ? schema.name() : null;
// Connect represents Timestamp, Time, and Date logical types as java.util.Date at runtime;
// normalize to Instant once, then interpret using the schema logical type name.
Instant connectInstant = date.toInstant();
if (org.apache.kafka.connect.data.Timestamp.LOGICAL_NAME.equals(logicalName)) {
return Variants.ofTimestamptz(DateTimeUtil.microsFromInstant(connectInstant));
}
if (org.apache.kafka.connect.data.Time.LOGICAL_NAME.equals(logicalName)) {
LocalTime utcTime = connectInstant.atZone(ZoneOffset.UTC).toLocalTime();
return Variants.ofTime(DateTimeUtil.microsFromTime(utcTime));
}
if (org.apache.kafka.connect.data.Date.LOGICAL_NAME.equals(logicalName)) {
return Variants.ofDate(DateTimeUtil.daysFromInstant(connectInstant));
}
throw new IllegalArgumentException(
"Cannot convert java.util.Date to variant without a recognized logical type schema"
+ " (expected Timestamp, Time, or Date but got: "
+ logicalName
+ ")");
}
return null;
}
/**
* Converts a Number to VariantValue; throw IllegalArgumentException if the value is not a
* supported number representation.
*/
private static VariantValue numberToVariantValue(Number number) {
if (number instanceof BigDecimal bigDecimal) {
return Variants.of(bigDecimal);
}
if (number instanceof BigInteger bigInteger) {
return Variants.of(new BigDecimal(bigInteger));View on GitHub (pinned to 86d9c8fc54)