{"record":{"id":"93b5f39d74aebf52","repo":"apache/iceberg","slug":"unsupported-time-unit-granularity","errorCode":null,"errorMessage":"Unsupported time unit: + granularity","messagePattern":"Unsupported time unit: \\+ granularity","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/transforms/Timestamps.java","lineNumber":78,"sourceCode":"    @Override\n    public Integer apply(Long timestamp) {\n      if (timestamp == null) {\n        return null;\n      }\n\n      switch (timestampUnit) {\n        case MICROS:\n          switch (granularity) {\n            case YEARS:\n              return DateTimeUtil.microsToYears(timestamp);\n            case MONTHS:\n              return DateTimeUtil.microsToMonths(timestamp);\n            case DAYS:\n              return DateTimeUtil.microsToDays(timestamp);\n            case HOURS:\n              return DateTimeUtil.microsToHours(timestamp);\n            default:\n              throw new UnsupportedOperationException(\"Unsupported time unit: \" + granularity);\n          }\n        case NANOS:\n          switch (granularity) {\n            case YEARS:\n              return DateTimeUtil.nanosToYears(timestamp);\n            case MONTHS:\n              return DateTimeUtil.nanosToMonths(timestamp);\n            case DAYS:\n              return DateTimeUtil.nanosToDays(timestamp);\n            case HOURS:\n              return DateTimeUtil.nanosToHours(timestamp);\n            default:\n              throw new UnsupportedOperationException(\"Unsupported time unit: \" + granularity);\n          }\n        default:\n          throw new UnsupportedOperationException(\"Unsupported time unit: \" + timestampUnit);\n      }\n    }","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java#L60-L96","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use only supported granularities: ChronoUnit.YEARS, MONTHS, DAYS, or HOURS for the transform (e.g. Transforms.day(\"ts\") instead of a raw ChronoUnit)","Validate any user-supplied granularity against Timestamps.SUPPORTED_GRANULARITIES before constructing the transform","Catch UnsupportedOperationException and surface a clear message that the granularity must be one of years/months/days/hours"],"exampleFix":"// before\nTransforms.timestamp(ChronoUnit.SECONDS, \"ts\");\n// after\nTransforms.day(\"ts\"); // supported granularities: year, month, day, hour","handlingStrategy":"validation","validationCode":"if (!Timestamps.SUPPORTED_GRANULARITIES.contains(granularity)) {\n  throw new IllegalArgumentException(\"Granularity must be one of \" + Timestamps.SUPPORTED_GRANULARITIES + \", got: \" + granularity);\n}","typeGuard":null,"tryCatchPattern":"try { Object v = tsTransform.bind(type).apply(value); } catch (UnsupportedOperationException e) { /* granularity unsupported: fall back to day() or rethrow with context */ }","preventionTips":["Only build timestamp transforms via Transforms.year/month/day/hour factories","Validate user-supplied granularity strings against Timestamps.SUPPORTED_GRANULARITIES before constructing ChronoUnit-based transforms","Never pass raw ChronoUnit values like SECONDS or MINUTES into Timestamps"],"tags":["java","iceberg","transform","unsupported-time-unit"],"backgroundTag":"unsupported-enum-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}