{"record":{"id":"63983df15b43a8be","repo":"apache/iceberg","slug":"found-already-bound-predicate","errorCode":null,"errorMessage":"Found already bound predicate: ","messagePattern":"Found already bound predicate: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/Binder.java","lineNumber":154,"sourceCode":"\n    @Override\n    public Expression not(Expression result) {\n      return Expressions.not(result);\n    }\n\n    @Override\n    public Expression and(Expression leftResult, Expression rightResult) {\n      return Expressions.and(leftResult, rightResult);\n    }\n\n    @Override\n    public Expression or(Expression leftResult, Expression rightResult) {\n      return Expressions.or(leftResult, rightResult);\n    }\n\n    @Override\n    public <T> Expression predicate(BoundPredicate<T> pred) {\n      throw new IllegalStateException(\"Found already bound predicate: \" + pred);\n    }\n\n    @Override\n    public <T> Expression predicate(UnboundPredicate<T> pred) {\n      return pred.bind(struct, caseSensitive);\n    }\n\n    @Override\n    public <T> Expression aggregate(UnboundAggregate<T> agg) {\n      return agg.bind(struct, caseSensitive);\n    }\n\n    @Override\n    public <T, C> Expression aggregate(BoundAggregate<T, C> agg) {\n      throw new IllegalStateException(\"Found already bound aggregate: \" + agg);\n    }\n  }\n","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/Binder.java#L136-L172","documentation":"Binder's predicate method is only supposed to receive UnboundPredicate instances, which it binds to a struct's schema. If an already-bound BoundPredicate is passed, it means the expression is being bound twice, which is a bug in the caller's logic, so Binder throws this IllegalStateException.","triggerScenarios":"Calling ExpressionBinder.bind() (or Expressions.bind) on an expression that was already bound, e.g. re-binding the result of a previous bind, or passing a BoundPredicate produced by a scan/residual evaluation into bind() a second time.","commonSituations":"Caching Expression objects and forgetting whether they were bound; applying residual-expression logic that feeds bound expressions back through Binder; framework code that binds user filters once at planning and again at execution.","solutions":["Bind each expression exactly once and reuse the BoundExpression result instead of re-binding","Track binding state (keep unbound and bound expressions in separate variables)","If unsure, use ExpressionVisitors.isBoundPredicate / expression().isBound() checks before calling bind","If the expression may already be bound, short-circuit: only call bind when !expr.isBound()"],"exampleFix":"// before\nExpression bound = Binder.bind(schema, expr, caseSensitive);\nExpression rebound = Binder.bind(schema, bound, caseSensitive); // throws\n// after\nExpression bound = Binder.bind(schema, expr, caseSensitive);\nif (!bound.isBound()) {\n  bound = Binder.bind(schema, bound, caseSensitive);\n}","handlingStrategy":"type-guard","validationCode":"if (expr.isBound()) { throw new IllegalArgumentException(\"expression already bound; pass an unbound expression\"); }","typeGuard":"boolean needsBinding = expr instanceof UnboundPredicate;","tryCatchPattern":"try { bound = Binder.bind(schema, expr, caseSensitive); } catch (IllegalStateException e) { if (e.getMessage().startsWith(\"Found already bound\")) { bound = expr; } else { throw e; } }","preventionTips":["Keep unbound and bound expressions in distinct variables/fields","Check Expression.isBound() before calling bind","Never feed residual/bound expressions back through Binder"],"tags":["expressions","binding","state-error"],"backgroundTag":"invalid-state-transition","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}