{"record":{"id":"f8fed75fa6ea327d","repo":"apache/iceberg","slug":"cannot-filter-timestamps-using-predicate","errorCode":null,"errorMessage":"Cannot filter timestamps using predicate: ","messagePattern":"Cannot filter timestamps using predicate: ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/ScanSummary.java","lineNumber":420,"sourceCode":"          if (value + 1 > minTimestamp) {\n            minTimestamp = value + 1;\n          }\n          break;\n        case GT_EQ:\n          if (value > minTimestamp) {\n            minTimestamp = value;\n          }\n          break;\n        case EQ:\n          if (value < maxTimestamp) {\n            maxTimestamp = value;\n          }\n          if (value > minTimestamp) {\n            minTimestamp = value;\n          }\n          break;\n        default:\n          throw new UnsupportedOperationException(\n              \"Cannot filter timestamps using predicate: \" + pred);\n      }\n    }\n\n    if (maxTimestamp < minTimestamp) {\n      throw new IllegalArgumentException(\n          \"No timestamps can match filters: \" + Joiner.on(\", \").join(timeFilters));\n    }\n\n    return Pair.of(minTimestamp, maxTimestamp);\n  }\n}\n","sourceCodeStart":402,"sourceCodeEnd":433,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/ScanSummary.java#L402-L433","documentation":"ScanSummary.timestampRange throws UnsupportedOperationException when it encounters a time-filter predicate it does not know how to convert into a timestamp range. Only a fixed set of comparison predicates (e.g. lt, lte, gt, gte, eq on the timestamp column) is supported.","triggerScenarios":"Passing expressions like not(), in, notIn, or compound/not-negation predicates on the timestamp metric to ScanSummary's time-based filtering.","commonSituations":"Building snapshot summaries with complex user-supplied filter expressions; using NOT or IN on timestamp filters expecting them to be handled.","solutions":["Rewrite the time filter using only supported comparison predicates (>, >=, <, <=, =).","Decompose NOT/IN expressions into equivalent comparisons before passing them.","Catch UnsupportedOperationException and fall back to an unbounded or manually computed range."],"exampleFix":"// before\nExpressions.not(Expressions.greaterThan(\"made_current_at\", startTs))\n// after\nExpressions.lessThanOrEqual(\"made_current_at\", startTs)","handlingStrategy":"validation","validationCode":"Set<Expression.Operation> supported = Set.of(LT, LT_EQ, GT, GT_EQ, EQ);\nExpression op = timeFilter;\nif (!supported.contains(op.op())) { throw new IllegalArgumentException(\"unsupported time filter: \" + op.op()); }","typeGuard":null,"tryCatchPattern":"try { Pair<Long,Long> range = ScanSummary.timestampRange(...); } catch (UnsupportedOperationException e) { /* rewrite predicate as comparisons */ }","preventionTips":["Express time filters only as comparison predicates","Avoid NOT/IN on timestamp metric filters","Unit-test filter expressions before passing to ScanSummary"],"tags":["iceberg","scan-summary","predicate","unsupported"],"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"}