{"record":{"id":"89f7b40c99feb25e","repo":"apache/iceberg","slug":"invalid-term-s-expected-either-a-bound-referenc","errorCode":null,"errorMessage":"Invalid term: %s, expected either a bound reference or transform","messagePattern":"Invalid term: (.+?), expected either a bound reference or transform","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java","lineNumber":370,"sourceCode":"    int sourceId = boundTerm.ref().fieldId();\n    Transform<?, ?> transform = toTransform(boundTerm);\n\n    Type fieldType = schema.findType(sourceId);\n    if (fieldType != null) {\n      transform = Transforms.fromString(fieldType, transform.toString());\n    } else {\n      transform = Transforms.fromString(transform.toString());\n    }\n    return Pair.of(sourceId, transform);\n  }\n\n  private Transform<?, ?> toTransform(BoundTerm<?> term) {\n    if (term instanceof BoundReference) {\n      return Transforms.identity();\n    } else if (term instanceof BoundTransform) {\n      return ((BoundTransform<?, ?>) term).transform();\n    } else {\n      throw new ValidationException(\n          \"Invalid term: %s, expected either a bound reference or transform\", term);\n    }\n  }\n\n  private void checkForRedundantAddedPartitions(PartitionField field) {\n    if (isTimeTransform(field)) {\n      PartitionField timeField = addedTimeFields.get(field.sourceId());\n      Preconditions.checkArgument(\n          timeField == null,\n          \"Cannot add redundant partition field: %s conflicts with %s\",\n          timeField,\n          field);\n      addedTimeFields.put(field.sourceId(), field);\n    }\n  }\n\n  private static Map<String, PartitionField> indexSpecByName(PartitionSpec spec) {\n    ImmutableMap.Builder<String, PartitionField> builder = ImmutableMap.builder();","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java#L352-L388","documentation":"toTransform converts a bound term into its Transform: identity for a plain BoundReference, or the wrapped transform for a BoundTransform. Any other bound term shape cannot be expressed as a transform, so a ValidationException naming the term is thrown. This happens when partition terms passed to the spec update are not simple references or transformed references.","triggerScenarios":"Calling transform(Term)/addField paths in BaseUpdatePartitionSpec with a term that resolves to neither BoundReference nor BoundTransform — typically a custom, aggregate, or wrongly-constructed bound term.","commonSituations":"Programmatic term construction producing unexpected bound term implementations; passing projected or aggregate terms where a simple column reference or transform is required.","solutions":["Build terms with Expressions.ref(column) or Expressions.transform(ref, transform) so they bind to BoundReference/BoundTransform","Check the bound term type before passing it into the spec update","Verify the term was bound against the table schema correctly"],"exampleFix":"// before\nTerm term = myCustomTermBuilder.build(); // not a BoundReference/BoundTransform\nspecUpdate.transform(term); // throws\n// after\nTerm term = Expressions.transform(Expressions.ref(\"ts\"), Expressions.day());\nspecUpdate.transform(term);","handlingStrategy":"validation","validationCode":"if (!(term instanceof BoundReference) && !(term instanceof BoundTransform)) { throw new IllegalArgumentException(\"term must be a reference or transform\"); }","typeGuard":null,"tryCatchPattern":"catch (ValidationException e) { /* rebuild the term with Expressions helpers */ }","preventionTips":["Always construct terms via the Expressions helper API","Bind terms against the table schema before passing to spec updates","Avoid custom Term implementations"],"tags":["validation","partition-spec","term"],"backgroundTag":"schema-validation-failed","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"}