{"record":{"id":"c32e678776f48c5b","repo":"apache/iceberg","slug":"cannot-truncate-type-type","errorCode":null,"errorMessage":"Cannot truncate type: + type","messagePattern":"Cannot truncate type: \\+ type","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/transforms/Truncate.java","lineNumber":66,"sourceCode":"   */\n  @Deprecated\n  @SuppressWarnings(\"unchecked\")\n  static <T, R extends Truncate<T> & SerializableFunction<T, T>> R get(Type type, int width) {\n    Preconditions.checkArgument(width > 0, \"Invalid truncate width: %s (must be > 0)\", width);\n\n    switch (type.typeId()) {\n      case INTEGER:\n        return (R) new TruncateInteger(width);\n      case LONG:\n        return (R) new TruncateLong(width);\n      case DECIMAL:\n        return (R) new TruncateDecimal(width);\n      case STRING:\n        return (R) new TruncateString(width);\n      case BINARY:\n        return (R) new TruncateByteBuffer(width);\n      default:\n        throw new UnsupportedOperationException(\"Cannot truncate type: \" + type);\n    }\n  }\n\n  @SuppressWarnings(\"checkstyle:VisibilityModifier\")\n  protected final int width;\n\n  Truncate(int width) {\n    this.width = width;\n  }\n\n  public Integer width() {\n    return width;\n  }\n\n  @Override\n  public T apply(T value) {\n    throw new UnsupportedOperationException(\n        \"apply(value) is deprecated, use bind(Type).apply(value)\");","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/transforms/Truncate.java#L48-L84","documentation":"Thrown by Truncate.get(Function applied to a type) when the target type is not one of the truncatable types — INTEGER/LONG (integers), DECIMAL, STRING, or BINARY. Truncation is only defined for those types; attempting to truncate e.g. a DATE, TIMESTAMP, or FLOAT fails fast rather than producing undefined behavior.","triggerScenarios":"Calling Truncate.of(width).bind(type) (which internally invokes get) with a type outside {IntegerType, LongType, DecimalType, StringType, BinaryType} — e.g. binding truncate to TimestampType or FloatType.","commonSituations":"Building a partition spec that truncates a timestamp or float column; dynamic spec construction where the column type comes from user input without validating truncatability.","solutions":["Only apply Truncate to INTEGER, LONG, DECIMAL, STRING, or BINARY columns","Check transform.canTransform(type) before binding and reject unsupported types with a clear message","Use the dedicated timestamp transforms (day/hour/etc.) for temporal columns instead of truncate"],"exampleFix":"// before\nTransforms.truncate(10).bind(TimestampType.get()); // throws\n// after\nTransforms.hour(\"ts\"); // or truncate on a string/binary/int column","handlingStrategy":"validation","validationCode":"if (!truncateTransform.canTransform(columnType)) {\n  throw new IllegalArgumentException(\"Cannot truncate type: \" + columnType + \"; use int/long/decimal/string/binary\");\n}","typeGuard":"boolean truncatable(Type t) {\n  return t.typeId() == Type.TypeID.INTEGER || t.typeId() == Type.TypeID.LONG\n      || t.typeId() == Type.TypeID.DECIMAL || t.typeId() == Type.TypeID.STRING\n      || t.typeId() == Type.TypeID.BINARY;\n}","tryCatchPattern":"try { fn = truncate.bind(type); } catch (UnsupportedOperationException e) { /* choose day()/hour() for temporal, or reject the spec */ }","preventionTips":["Check canTransform(type) before binding any transform","Use date/hour transforms for temporal columns instead of truncate","Validate partition spec columns against truncatable types when specs come from user input"],"tags":["java","iceberg","transform","truncate","unsupported-type"],"backgroundTag":"unsupported-operation","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"}