{"record":{"id":"d0e5e4934d7f2482","repo":"apache/iceberg","slug":"void-transform-is-not-supported","errorCode":null,"errorMessage":"Void transform is not supported","messagePattern":"Void transform is not supported","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/transforms/PartitionSpecVisitor.java","lineNumber":85,"sourceCode":"\n  default T day(int fieldId, String sourceName, int sourceId) {\n    return day(sourceName, sourceId);\n  }\n\n  default T day(String sourceName, int sourceId) {\n    throw new UnsupportedOperationException(\"Day transform is not supported\");\n  }\n\n  default T hour(int fieldId, String sourceName, int sourceId) {\n    return hour(sourceName, sourceId);\n  }\n\n  default T hour(String sourceName, int sourceId) {\n    throw new UnsupportedOperationException(\"Hour transform is not supported\");\n  }\n\n  default T alwaysNull(int fieldId, String sourceName, int sourceId) {\n    throw new UnsupportedOperationException(\"Void transform is not supported\");\n  }\n\n  default T unknown(int fieldId, String sourceName, int sourceId, String transform) {\n    throw new UnsupportedOperationException(\n        String.format(\"Unknown transform %s is not supported\", transform));\n  }\n\n  /**\n   * Visit the fields of a {@link PartitionSpec}.\n   *\n   * @param spec a partition spec to visit\n   * @param visitor a partition spec visitor\n   * @param <R> return type of the visitor\n   * @return a list of the result produced by visiting each partition field\n   */\n  static <R> List<R> visit(PartitionSpec spec, PartitionSpecVisitor<R> visitor) {\n    List<R> results = Lists.newArrayListWithExpectedSize(spec.fields().size());\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/transforms/PartitionSpecVisitor.java#L67-L103","documentation":"PartitionSpecVisitor's default alwaysNull() throws UnsupportedOperationException for partition fields using the Void transform. A Void transform results from partition-field evolution: a field is removed from the spec by replacing its transform with void, leaving the column all nulls. Dispatch in visit() matches VoidTransform and calls alwaysNull(); implementations that ignore void fields fail here unless they explicitly handle them.","triggerScenarios":"PartitionSpecVisitor.visit on a table whose partition spec contains a void transform — i.e. a partition field was removed via updatePartitionSpec/removeField and later the spec is visited by a visitor without an alwaysNull override.","commonSituations":"Tables whose partitioning was evolved (dropped/changed partition fields) visited by catalog translators that were written for specs with only live transforms; copying such a spec to a target catalog that cannot represent void fields.","solutions":["Override alwaysNull(int fieldId, String sourceName, int sourceId) to emit the appropriate representation (e.g. a null-valued partition column or skip the field)","Filter spec.fields() for transform instanceof VoidTransform before visiting and decide how to map them","If the target cannot represent void partition fields, remap or drop them in the visitor implementation explicitly"],"exampleFix":"// before\nvisitor without alwaysNull override -> UnsupportedOperationException on evolved spec\n// after\n@Override\npublic String alwaysNull(int fieldId, String sourceName, int sourceId) {\n  return null; // void partition field: all values are null\n}","handlingStrategy":"validation","validationCode":"boolean hasVoidTransform(PartitionSpec spec) {\n  return spec.fields().stream().anyMatch(f -> f.transform() instanceof VoidTransform);\n}\n// indicates an evolved spec; decide before visiting how void fields map","typeGuard":"if (field.transform() instanceof VoidTransform) {\n  // emit null representation or skip — do not rely on the throwing default\n}","tryCatchPattern":"try {\n  PartitionSpecVisitor.visit(spec, visitor);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"Void\")) {\n    LOG.warn(\"Spec has void partition fields (partition evolution); adjust visitor\");\n  }\n  throw e;\n}","preventionTips":["Remember specs evolve: removed fields become void, so old visitors break on old tables","Always override alwaysNull() in production visitors","Round-trip test: evolve a spec (remove a field), then run the visitor"],"tags":["java","partitioning","partition-evolution","void-transform"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}