{"record":{"id":"00ad533b6926639c","repo":"apache/iceberg","slug":"cannot-sanitize-bound-predicate-type-operation","errorCode":null,"errorMessage":"Cannot sanitize bound predicate type: ${operation}","messagePattern":"Cannot sanitize bound predicate type: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java","lineNumber":385,"sourceCode":"    public <T> Expression predicate(BoundPredicate<T> pred) {\n      if (pred.isUnaryPredicate()) {\n        // unary predicates don't need to be sanitized\n        return new UnboundPredicate<>(pred.op(), unbind(pred.term()));\n      } else if (pred.isLiteralPredicate()) {\n        BoundLiteralPredicate<T> bound = (BoundLiteralPredicate<T>) pred;\n        return new UnboundPredicate<>(\n            pred.op(), unbind(pred.term()), (T) sanitize(bound.literal(), now, today));\n      } else if (pred.isSetPredicate()) {\n        BoundSetPredicate<T> bound = (BoundSetPredicate<T>) pred;\n        Iterable<T> iter =\n            () ->\n                bound.literalSet().stream()\n                    .map(lit -> (T) sanitize((Literal<?>) lit, now, today))\n                    .iterator();\n        return new UnboundPredicate<>(pred.op(), unbind(pred.term()), iter);\n      }\n\n      throw new UnsupportedOperationException(\"Cannot sanitize bound predicate type: \" + pred.op());\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> Expression predicate(UnboundPredicate<T> pred) {\n      switch (pred.op()) {\n        case IS_NULL:\n        case NOT_NULL:\n        case IS_NAN:\n        case NOT_NAN:\n          // unary predicates don't need to be sanitized\n          return pred;\n        case LT:\n        case LT_EQ:\n        case GT:\n        case GT_EQ:\n        case EQ:\n        case NOT_EQ:","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java#L367-L403","documentation":"The bound-predicate sanitizer in ExpressionUtil only supports bound predicates whose operation takes literals (eq, lt, in, etc.). Operations without bound literal representation (e.g. startsWith on some paths, or count/null ops reached here unexpectedly) fall through to this UnsupportedOperationException.","triggerScenarios":"Running ExpressionUtil.sanitize over a bound predicate whose ExpressionOperation is not one the sanitizer switch handles (e.g. STARTS_WITH/NOT_STARTS_WITH or other unhandled bound ops in that visitor).","commonSituations":"Sanitizing query strings for logging while using string predicates (startsWith) that the bound sanitizer branch does not cover; version drift where new operations were added but the sanitizer was not updated.","solutions":["Upgrade Iceberg — newer versions extend the sanitizer to more bound operations","Sanitize the expression before binding (use the unbound predicate sanitizer path) instead of after","Pre-check pred.op() and skip/handle unsupported operations before sanitizing","If sanitizing for logging, fall back to describing the predicate without value redaction for unsupported ops"],"exampleFix":"// before\nExpression safe = ExpressionUtil.sanitize(boundStartsWithPredicate, now, today);\n// after\nExpression safe = pred.op() == Expression.Operation.STARTS_WITH\n    ? pred // handle or skip unsupported op\n    : ExpressionUtil.sanitize(pred, now, today);","handlingStrategy":"try-catch","validationCode":"Expression.Operation op = pred.op();\nif (op == Expression.Operation.STARTS_WITH || op == Expression.Operation.NOT_STARTS_WITH) {\n  throw new IllegalArgumentException(\"sanitize() does not support bound op: \" + op);\n}","typeGuard":null,"tryCatchPattern":"try { return ExpressionUtil.sanitize(expr, now, today); }\ncatch (UnsupportedOperationException e) { return expr; /* unsanitized fallback */ }","preventionTips":["Pre-check Expression.Operation against supported sanitizer ops","Sanitize before binding when possible","Upgrade Iceberg when using newer predicate operations"],"tags":["expressions","sanitizer"],"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"}