apache/iceberg · error · ConnectException
Cannot convert date
Error message
Cannot convert date: ${value} What it means
RecordConverter.convertDateValue throws this ConnectException when a value mapped to an Iceberg Date column is not a Number (days since epoch), LocalDate, java.util.Date, or a parseable date string. The sink cannot interpret the value as a calendar date.
Solutions
- Ensure the Connect schema declares the field as int32 with the Date logical type (or int32 days / string date)
- Use TimestampConverter SMT to normalize the value to Date/unix time before the sink
- Fix the source record so the date is an ISO-8601 string or epoch-days number
- Verify the field mapping in the connector config hasn't shifted to a different field
Example fix
// before SchemaBuilder.string().build(); // "not-a-date" reaches convertDateValue // after Date.Builder logical = Date.builder().schema(SchemaBuilder.int32().build()); // epoch days
Defensive patterns
Strategy: validation
Validate before calling
// check before sink
Object v = record.value().get("dateField");
if (!(v instanceof Number || v instanceof LocalDate || v instanceof java.util.Date || v instanceof String)) {
throw new IllegalStateException("Date field bad type: " + (v == null ? "null" : v.getClass()));
} Type guard
static boolean isDateCompatible(Object v) {
return v == null || v instanceof Number || v instanceof LocalDate
|| v instanceof java.util.Date || v instanceof String;
} Try / catch
try {
converter.convertValue(value, Types.DateType.get());
} catch (ConnectException e) {
log.error("Date conversion failed: " + e.getMessage(), e);
// send to dead-letter queue instead of failing the task
} Prevention
- Use Connect Date logical type (int32 epoch days)
- Run TimestampConverter SMT for temporal normalization
- Pin producer schema in Schema Registry to the Date logical type
- Test schema evolution changes against the sink before rollout
When it happens
Trigger: A Date field receives a nested struct, map, boolean, or arbitrary object; or a String that fails date parsing reaches convertDateValue via convertValue or ts (timestamp-to-date coercion).
Common situations: Producer schema changed a date field to a complex type; Connect's JSON converter delivered an unparsed string or object; an SMT cast a timestamp into the wrong field that the sink maps to Date.
Related errors
- Cannot convert time
- Cannot convert timestamp
- Cannot convert timestamptz
- Cannot convert to binary
- Cannot convert to double
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/c3a25b330b41269e.
Report an issue: GitHub.
Appendix: source
Thrown at kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordConverter.java:552
return (ByteBuffer) value;
}
throw new IllegalArgumentException("Cannot convert to binary: " + value.getClass().getName());
}
@SuppressWarnings("JavaUtilDate")
protected LocalDate convertDateValue(Object value) {
if (value instanceof Number) {
int days = ((Number) value).intValue();
return DateTimeUtil.dateFromDays(days);
} else if (value instanceof String) {
return LocalDate.parse((String) value);
} else if (value instanceof LocalDate) {
return (LocalDate) value;
} else if (value instanceof Date) {
int days = (int) (((Date) value).getTime() / 1000 / 60 / 60 / 24);
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);
}
View on GitHub (pinned to 86d9c8fc54)