apache/druid · error · CNFFilterExplosionException

Exceeded maximum allowed filters for CNF (conjunctive…

Error message

Exceeded maximum allowed filters for CNF (conjunctive normal form) conversion

What it means

HiveCnfHelper.convertToCnfWithLimit throws CNFFilterExplosionException when converting a filter's AND branch to CNF would exceed maxCNFFilterLimit (the budget of filters allowed after expansion). CNF conversion of nested boolean filters can blow up combinatorially, so Druid bounds it. This prevents query planning from consuming unbounded memory/time.

Solutions

  1. Simplify the boolean filter expression before conversion (flatten redundant AND/OR nesting)
  2. Increase the max CNF filter limit configuration if appropriate for your workload
  3. Split the query into smaller queries with fewer boolean conditions

Example fix

// before
Filters.toCnf(hugeNestedFilter, 50); // exceeds limit of 50
// after
Filter simplified = Filters.flatten(hugeNestedFilter);
Filters.toCnf(simplified, 1000); // raised limit + simplified tree
Defensive patterns

Strategy: try-catch

Validate before calling

int estimated = estimateCnfSize(filter); if (estimated > maxCnfFilterLimit) { /* simplify or split first */ }

Try / catch

try { cnf = Filters.toCnf(filter, limit); } catch (CNFFilterExplosionException e) { cnf = filter; /* fall back to unconverted filter */ }

Prevention

When it happens

Trigger: Running Filters.toCnf (or query translation that uses it) on an AndFilter whose subtree, once recursively converted, would produce more than the configured CNF filter limit.

Common situations: Queries with large OR-of-AND expressions (many disjunctive predicates); nested boolean expressions from generated SQL; low server-side CNF limit settings.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/cae4db0f17ef67b0. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/filter/cnf/HiveCnfHelper.java:111

   * @throws CNFFilterExplosionException is thrown if the filters in CNF representation go beyond maxCNFFilterLimit
   */
  private static NonnullPair<Filter, Integer> convertToCnfWithLimit(
      Filter current,
      int maxCNFFilterLimit
  ) throws CNFFilterExplosionException
  {
    if (current instanceof NotFilter) {
      NonnullPair<Filter, Integer> result = convertToCnfWithLimit(((NotFilter) current).getBaseFilter(), maxCNFFilterLimit);
      return new NonnullPair<>(new NotFilter(result.lhs), result.rhs);
    }
    if (current instanceof AndFilter) {
      List<Filter> children = new ArrayList<>();
      for (Filter child : ((AndFilter) current).getFilters()) {
        NonnullPair<Filter, Integer> result = convertToCnfWithLimit(child, maxCNFFilterLimit);
        children.add(result.lhs);
        maxCNFFilterLimit = result.rhs;
        if (maxCNFFilterLimit < 0) {
          throw new CNFFilterExplosionException("Exceeded maximum allowed filters for CNF (conjunctive normal form) conversion");
        }
      }
      return new NonnullPair<>(Filters.and(children), maxCNFFilterLimit);
    }
    if (current instanceof OrFilter) {
      // a list of leaves that weren't under AND expressions
      List<Filter> nonAndList = new ArrayList<>();
      // a list of AND expressions that we need to distribute
      List<Filter> andList = new ArrayList<>();
      for (Filter child : ((OrFilter) current).getFilters()) {
        if (child instanceof AndFilter) {
          andList.add(child);
        } else if (child instanceof OrFilter) {
          // pull apart the kids of the OR expression
          nonAndList.addAll(((OrFilter) child).getFilters());
        } else {
          nonAndList.add(child);
        }

View on GitHub (pinned to 9b90983fd2)