apache/beam · error · java.lang.IllegalArgumentException
Does not support table_valued function
Error message
Does not support table_valued function: %s
What it means
BeamTableFunctionScanRel supports only a limited set of table-valued functions (e.g. Tumble, Session, FixedWindow TVFs, and ZetaSQL native TVFs that pass input through). When expand() encounters a TVF operator it doesn't implement, it throws this IllegalArgumentException naming the unsupported operator.
Solutions
- Use one of the supported TVFs (e.g. TUMBLE, HOP, SESSION windowing functions) instead of the unsupported one.
- If it's a ZetaSQL native TVF, ensure it resolves to ZetaSqlUserDefinedSQLNativeTableValuedFunction so input passes through.
- Implement a BeamSqlTableFunction (and a matching Calcite operator) for the desired TVF if extending Beam.
- Rewrite the query using regular joins/aggregations/Window transforms to achieve the same effect.
Defensive patterns
Strategy: validation
Validate before calling
SqlOperator op = ((RexCall) call).getOperator(); if (!(op instanceof BeamSqlTableFunction) && !(op instanceof ZetaSqlUserDefinedSQLNativeTableValuedFunction)) { throw new IllegalArgumentException("Unsupported TVF: " + op.getName()); } Type guard
boolean isSupportedTvf = operator instanceof BeamSqlTableFunction || operator instanceof ZetaSqlUserDefinedSQLNativeTableValuedFunction;
Try / catch
try { result = pipeline.apply(SqlTransform.query(sql)); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Does not support table_valued function")) { /* rewrite with supported TVFs or transforms */ } else { throw e; } } Prevention
- Restrict queries to the TVFs Beam implements (TUMBLE/HOP/SESSION and registered native TVFs)
- Register a BeamSqlTableFunction implementation for any custom TVF before using it
- Check ZetaSQL TVF resolution so native TVFs pass through as expected
- Maintain a whitelist of allowed TVF operators for user-submitted SQL
When it happens
Trigger: Invoking a table-valued function in BeamSql whose operator is not one of the supported windowing/TVF implementations — e.g. a custom or ZetaSQL TVF not registered as a native pass-through — during translation of the TableFunctionScan.
Common situations: Using TVF syntax from ZetaSQL (like APPENDS or vendor-specific TVFs) against BeamSql, or calling a user-registered TVF that only has a UDF binding but no BeamSqlTableFunction implementation.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot drop catalog: ' ' not found.
- Cannot use catalog: ' ' not found.
- Catalog ' ' already exists.
- 'CREATE TABLE' is not supported in SQL. You can use 'CREATE…
- Data type: not supported yet!
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/4139da1c7eed75d3.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rel/BeamTableFunctionScanRel.java:219
"Wrong number of inputs for %s, expected 1 input but received: %s",
BeamTableFunctionScanRel.class.getSimpleName(),
input);
String operatorName = ((RexCall) getCall()).getOperator().getName();
// builtin TVF uses existing PTransform implementations.
if (tvfToPTransformMap.keySet().contains(operatorName)) {
return tvfToPTransformMap
.get(operatorName)
.toPTransform(((RexCall) getCall()), input.get(0));
}
// ZetaSQL pure SQL TVF should pass through input to output.
if (((RexCall) getCall()).getOperator()
instanceof ZetaSqlUserDefinedSQLNativeTableValuedFunction) {
return input.get(0);
}
throw new IllegalArgumentException(
String.format("Does not support table_valued function: %s", operatorName));
}
private Schema getKeySchema(Schema inputSchema, List<Integer> keys) {
List<Field> fields = new ArrayList<>();
for (Integer i : keys) {
fields.add(inputSchema.getField(i));
}
return Schema.builder().addFields(fields).build();
}
/** Extract timestamps from the windowFieldIndex, then window into windowFns. */
private PCollection<Row> assignTimestampsAndWindow(
PCollection<Row> upstream, int windowFieldIndex, WindowFn<Row, IntervalWindow> windowFn) {
PCollection<Row> windowedStream;
windowedStream =
upstream
.apply(View on GitHub (pinned to 12126d8942)