apache/beam · error · IllegalArgumentException

Unable to unparse with operands.

Error message

Unable to unparse %s with %d operands.

What it means

BeamBigQuerySqlDialect.unparseFunctionsUsingInterval only knows how to unparse interval-function calls with exactly three operands (function name, first arg, INTERVAL qualifier). Any other operand count produces this IllegalArgumentException, naming the operator and the actual operand count.

Solutions

  1. Rewrite the query to use standard 3-operand interval function forms supported by the dialect
  2. Simplify interval expressions to INTERVAL n UNIT literals
  3. Extend BeamBigQuerySqlDialect.unparseFunctionsUsingInterval to handle the extra operand shapes

Example fix

// before (dialect-side)
throw new IllegalArgumentException(...);
// after: handle 2-operand form
if (operandCount == 2) { call.operand(1).unparse(writer, leftPrec, rightPrec); writer.endFunCall(frame); return; }
Defensive patterns

Strategy: validation

Validate before calling

// before unparse
if (call.getOperands().size() != 3) {
  throw new IllegalArgumentException("interval function " + call.getOperator().getName() + " must have 3 operands for BigQuery dialect");
}

Type guard

boolean isThreeOperandInterval(RexCall call) { return call.getOperands().size() == 3; }

Try / catch

try {
  dialect.unparseCall(writer, call, left, right);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Unable to unparse")) { /* fall back to generic unparse */ }
  throw e;
}

Prevention

When it happens

Trigger: Unparsing a SQL call routed to unparseFunctionsUsingInterval (via unparseCall) whose operand count is not the expected 3 — e.g. a custom or Calcite-generated operator variant of an interval function with 2 or 4 operands.

Common situations: Using interval arithmetic forms the dialect doesn't model (unary interval expressions, extra precision modifiers); Calcite rewrites producing differently-shaped RexCall nodes before unparse; version mismatches between Calcite and Beam's dialect.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/bigquery/BeamBigQuerySqlDialect.java:190

    // TIMESTAMP_ADD(timestamp_expression, INTERVAL int64_expression date_part)
    int operandCount = call.operandCount();
    if (operandCount == 2) {
      // operand0: timestamp_expression
      // operand1: SqlIntervalLiteral (INTERVAL int64_expression date_part)
      super.unparseCall(writer, call, leftPrec, rightPrec);
    } else if (operandCount == 3) {
      // operand0: timestamp_expression
      // operand1: int64_expression
      // operand2: date_part
      final SqlWriter.Frame frame = writer.startFunCall(call.getOperator().getName());
      call.operand(0).unparse(writer, leftPrec, rightPrec);
      writer.literal(",");
      writer.literal("INTERVAL");
      call.operand(1).unparse(writer, leftPrec, rightPrec);
      call.operand(2).unparse(writer, leftPrec, rightPrec);
      writer.endFunCall(frame);
    } else {
      throw new IllegalArgumentException(
          String.format(
              "Unable to unparse %s with %d operands.",
              call.getOperator().getName(), operandCount));
    }
  }

  private void unparseExtractFunctions(
      SqlWriter writer, SqlCall call, int leftPrec, int rightPrec) {
    String funName = call.getOperator().getName();
    int operandCount = call.operandCount();
    SqlNode tz = null;

    final SqlWriter.Frame frame = writer.startFunCall("EXTRACT");
    if (!funName.equals("$extract") && (operandCount == 1 || operandCount == 2)) {
      // EXTRACT(DATE/TIME/DATETIME FROM timestamp_expression [AT TIME ZONE tz])
      // operand0: timestamp_expression
      // operand1: tz (optional)
      writer.literal(EXTRACT_FUNCTIONS.get(funName));

View on GitHub (pinned to 12126d8942)