apache/iceberg · error · UnsupportedOperationException
Unsupported time unit:
Error message
Unsupported time unit:
What it means
Dates.DateToYearsTransform (and sibling date transforms) apply only to a fixed set of granularities: YEARS, MONTHS, DAYS. If apply() encounters any other ChronoUnit, Iceberg throws UnsupportedOperationException. This indicates the transform was constructed or dispatched with a granularity the date transform does not implement.
Source
Thrown at api/src/main/java/org/apache/iceberg/transforms/Dates.java:61
Apply(ChronoUnit granularity) {
this.granularity = granularity;
}
@Override
public Integer apply(Integer days) {
if (days == null) {
return null;
}
switch (granularity) {
case YEARS:
return DateTimeUtil.daysToYears(days);
case MONTHS:
return DateTimeUtil.daysToMonths(days);
case DAYS:
return days;
default:
throw new UnsupportedOperationException("Unsupported time unit: " + granularity);
}
}
}
private final ChronoUnit granularity;
private final String name;
private final Apply apply;
Dates(ChronoUnit granularity, String name) {
this.granularity = granularity;
this.name = name;
this.apply = new Apply(granularity);
}
/**
* Transforms a value to its corresponding partition value.
*
* @param days a source valueView on GitHub (pinned to 86d9c8fc54)
Solutions
- Use the correct transform family: Dates for day-granularity sources, Hours for hour sources, or a timestamp transform for finer units.
- Validate granularity is one of ChronoUnit.YEARS/MONTHS/DAYS before constructing/calling the date transform.
- Catch UnsupportedOperationException at dispatch boundaries when translating unknown granularities.
Example fix
// before Transform<Integer, Integer> t = Dates.from(granularity); // granularity = HOURS Integer out = t.apply(days); // after Preconditions.checkArgument(granularity == ChronoUnit.YEARS || granularity == ChronoUnit.MONTHS || granularity == ChronoUnit.DAYS, "Invalid date granularity: %s", granularity); Transform<Integer, Integer> t = Dates.from(granularity);
Defensive patterns
Strategy: validation
Validate before calling
if (granularity != ChronoUnit.YEARS && granularity != ChronoUnit.MONTHS && granularity != ChronoUnit.DAYS) { throw new IllegalArgumentException("Invalid date granularity: " + granularity); } Type guard
boolean isDateGranularity(ChronoUnit u) { return u == ChronoUnit.YEARS || u == ChronoUnit.MONTHS || u == ChronoUnit.DAYS; } Try / catch
try { return dateTransform.apply(days); } catch (UnsupportedOperationException e) { throw new IllegalArgumentException("Granularity not supported by date transform", e); } Prevention
- Route HOUR-granularity data to the Hours transform, not Dates
- Validate granularity when parsing transforms from strings
- Enumerate supported granularities in a constant set and check membership
When it happens
Trigger: Building a Dates transform (e.g. via TransformUtil or parsing) with a granularity outside YEARS/MONTHS/DAYS (e.g. HOURS, MINUTES), then calling apply(days).
Common situations: Parsing partition field transforms from strings or specs where an invalid granularity slipped in; generic transform-dispatch code reusing a date transform for hour-level source data (which belongs to the Hours/ timestamps transforms).
Related errors
- hash(value) is not supported on the base Bucket class
- Can't retrieve values from an empty struct
- Can't modify an empty struct
- %s doesn't implement cleanupLevel
- %s doesn't implement cleanExpiredMetadata
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/fcb49093474a47d9.
Report an issue: GitHub.