apache/iceberg · error

Unsupported time unit: + granularity

Error message

Unsupported time unit: + granularity

What it means

Thrown by the bound Timestamps transform's apply() when a ChronoUnit granularity is not one of the supported time granularities (YEARS, MONTHS, DAYS, HOURS) for the microsecond timestamp branch. Iceberg bucket/time transforms only support a fixed set of ChronoUnit granularities, so any other unit (e.g. SECONDS, MINUTES, NANOS granularity on the MICROS branch) cannot be applied. This is a guard against constructing a Timestamps transform with an unsupported granularity.

Source

Thrown at api/src/main/java/org/apache/iceberg/transforms/Timestamps.java:78

    @Override
    public Integer apply(Long timestamp) {
      if (timestamp == null) {
        return null;
      }

      switch (timestampUnit) {
        case MICROS:
          switch (granularity) {
            case YEARS:
              return DateTimeUtil.microsToYears(timestamp);
            case MONTHS:
              return DateTimeUtil.microsToMonths(timestamp);
            case DAYS:
              return DateTimeUtil.microsToDays(timestamp);
            case HOURS:
              return DateTimeUtil.microsToHours(timestamp);
            default:
              throw new UnsupportedOperationException("Unsupported time unit: " + granularity);
          }
        case NANOS:
          switch (granularity) {
            case YEARS:
              return DateTimeUtil.nanosToYears(timestamp);
            case MONTHS:
              return DateTimeUtil.nanosToMonths(timestamp);
            case DAYS:
              return DateTimeUtil.nanosToDays(timestamp);
            case HOURS:
              return DateTimeUtil.nanosToHours(timestamp);
            default:
              throw new UnsupportedOperationException("Unsupported time unit: " + granularity);
          }
        default:
          throw new UnsupportedOperationException("Unsupported time unit: " + timestampUnit);
      }
    }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use only supported granularities: ChronoUnit.YEARS, MONTHS, DAYS, or HOURS for the transform (e.g. Transforms.day("ts") instead of a raw ChronoUnit)
  2. Validate any user-supplied granularity against Timestamps.SUPPORTED_GRANULARITIES before constructing the transform
  3. Catch UnsupportedOperationException and surface a clear message that the granularity must be one of years/months/days/hours

Example fix

// before
Transforms.timestamp(ChronoUnit.SECONDS, "ts");
// after
Transforms.day("ts"); // supported granularities: year, month, day, hour
Defensive patterns

Strategy: validation

Validate before calling

if (!Timestamps.SUPPORTED_GRANULARITIES.contains(granularity)) {
  throw new IllegalArgumentException("Granularity must be one of " + Timestamps.SUPPORTED_GRANULARITIES + ", got: " + granularity);
}

Try / catch

try { Object v = tsTransform.bind(type).apply(value); } catch (UnsupportedOperationException e) { /* granularity unsupported: fall back to day() or rethrow with context */ }

Prevention

When it happens

Trigger: Calling Timestamps.of(ChronoUnit.MICROS).bind(...).apply() (via the generated function) where the switch granularity falls through to default — i.e. granularity is SECONDS, MINUTES, NANOS, or any non-supported ChronoUnit rather than YEARS/MONTHS/DAYS/HOURS.

Common situations: Programmatically building transforms from user-supplied granularity strings mapped to ChronoUnit without validating against the supported set (ChronoUnit.SECONDS or MINUTES are natural but unsupported choices); deserializing a transform spec from a hand-written partition spec with an unsupported granularity name.

Related errors


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