apache/beam · error · SqlConversionException

Unable to convert query %s

Error message

Unable to convert query %s

What it means

CalciteQueryPlanner.convertToBeamRel() catches RelConversionException and CannotPlanException from Calcite's planning/optimization pipeline and rethrows them as SqlConversionException with the SQL statement. The SQL parsed but Calcite/Beam could not convert the validated relational tree into an executable BeamRelNode — typically an unsupported relational construct or a trait-conversion/planning failure. This signals a planning problem, not a syntax error.

Source

Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/CalciteQueryPlanner.java:238

              .simplify();
      // beam physical plan
      relNode
          .getCluster()
          .setMetadataProvider(
              ChainedRelMetadataProvider.of(
                  ImmutableList.of(
                      NonCumulativeCostImpl.SOURCE,
                      RelMdNodeStats.SOURCE,
                      relNode.getCluster().getMetadataProvider())));

      relNode.getCluster().setMetadataQuerySupplier(BeamRelMetadataQuery::instance);
      RelMetadataQuery.THREAD_PROVIDERS.set(
          JaninoRelMetadataProvider.of(relNode.getCluster().getMetadataProvider()));
      relNode.getCluster().invalidateMetadataQuery();
      beamRelNode = (BeamRelNode) planner.transform(0, desiredTraits, relNode);
      LOG.info("BEAMPlan>\n{}", BeamSqlRelUtils.explainLazily(beamRelNode));
    } catch (RelConversionException | CannotPlanException e) {
      throw new SqlConversionException(
          String.format("Unable to convert query %s", sqlStatement), e);
    } catch (SqlParseException | ValidationException e) {
      throw new ParseException(String.format("Unable to parse query %s", sqlStatement), e);
    } finally {
      planner.close();
    }
    return beamRelNode;
  }

  private static RelNode bindParameters(RelNode rel, RexShuttle binder) {
    RelNode newRel = rel.accept(binder);
    java.util.List<RelNode> newInputs = new java.util.ArrayList<>();
    for (RelNode input : newRel.getInputs()) {
      newInputs.add(bindParameters(input, binder));
    }
    return newRel.copy(newRel.getTraitSet(), newInputs);
  }

View on GitHub (pinned to 12126d8942)

Solutions

  1. Rewrite the query to avoid the unsupported construct identified in the exception cause.
  2. Simplify or split the query, computing the unsupported part outside SQL.
  3. Check Beam SQL supported-features docs for the specific operator.
  4. Upgrade Beam — unsupported operators are added over time.

Example fix

// before
pipeline.apply(SqlTransform.query("SELECT * FROM t ASOF JOIN u ..."));
// after
pipeline.apply(SqlTransform.query("SELECT * FROM t JOIN u ON t.k = u.k"));
Defensive patterns

Strategy: try-catch

Validate before calling

// no direct pre-check API; keep queries within documented supported operators
// and test complex queries against the exact Beam version in CI

Try / catch

try {
  BeamRelNode beamRel = planner.convertToBeamRel(sqlStatement);
} catch (SqlConversionException e) {
  LOG.error("Cannot plan query [{}]: {}", sqlStatement, e.getCause().getMessage());
  throw e;
}

Prevention

When it happens

Trigger: Calling convertToBeamRel(String sqlStatement) where the validated plan cannot be transformed to Beam traits (planner.transform(0, desiredTraits, relNode) throws RelConversionException) or cannot be produced (CannotPlanException).

Common situations: Queries with relational operators Beam SQL does not implement (exotic JOINs, unsupported windowing); queries referencing unsupported table expressions; hints/features Calcite cannot satisfy under Beam's convention traits.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/1a156dc08335a78b. Report an issue: GitHub.