apache/beam · error · java.lang.UnsupportedOperationException
FULL OUTER JOIN is not supported when join a bounded table w
Error message
FULL OUTER JOIN is not supported when join a bounded table with an unbounded table.
What it means
BeamSideInputJoinRel handles joins between a bounded and an unbounded PCollection via side inputs, which only supports INNER, LEFT OUTER (unbounded left), and RIGHT OUTER (unbounded right) joins. A FULL OUTER JOIN in this bounded/unbounded mix cannot be materialized as a side input, so buildPTransform throws UnsupportedOperationException.
Source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rel/BeamSideInputJoinRel.java:102
RelTraitSet traitSet,
RexNode conditionExpr,
RelNode left,
RelNode right,
JoinRelType joinType,
boolean semiJoinDone) {
return new BeamSideInputJoinRel(
getCluster(), traitSet, left, right, conditionExpr, variablesSet, joinType);
}
@Override
public PTransform<PCollectionList<Row>, PCollection<Row>> buildPTransform() {
// if one of the sides is Bounded & the other is Unbounded
// then do a sideInput join.
// When doing a sideInput join, the windowFn does not need to match.
// Only support INNER JOIN & LEFT OUTER JOIN where left side of the join must be
// the unbounded & RIGHT OUTER JOIN where right side of the join must be the unbounded
if (joinType == JoinRelType.FULL) {
throw new UnsupportedOperationException(
"FULL OUTER JOIN is not supported when join "
+ "a bounded table with an unbounded table.");
}
BeamRelNode leftRelNode = BeamSqlRelUtils.getBeamRelInput(left);
BeamRelNode rightRelNode = BeamSqlRelUtils.getBeamRelInput(right);
if ((joinType == JoinRelType.LEFT && leftRelNode.isBounded() == PCollection.IsBounded.BOUNDED)
|| (joinType == JoinRelType.RIGHT
&& rightRelNode.isBounded() == PCollection.IsBounded.BOUNDED)) {
throw new UnsupportedOperationException(
String.format("%s side of an OUTER JOIN must be Unbounded table.", joinType.name()));
}
if (leftRelNode.isBounded() == IsBounded.UNBOUNDED
&& rightRelNode.isBounded() == IsBounded.UNBOUNDED) {
throw new UnsupportedOperationException(
"Side input join can only be used if one table is bounded.");
}View on GitHub (pinned to 12126d8942)
Solutions
- Rewrite as LEFT OUTER JOIN with the unbounded relation on the left (semantically equivalent orientation where possible)
- Union the unmatched sides manually: run an INNER side-input join plus separate filters for non-matching rows on each side, then UNION the results
- Make both sides bounded (batch mode) or both unbounded with compatible windows so a different join implementation is chosen
Example fix
// before SELECT * FROM streaming_events FULL OUTER JOIN batch_dim ON streaming_events.k = batch_dim.k; // after SELECT s.*, d.* FROM streaming_events s LEFT OUTER JOIN batch_dim d ON s.k = d.k; -- plus a separate query for unmatched dim rows if truly needed
Defensive patterns
Strategy: validation
Validate before calling
// Check boundedness + join type before submitting
if (joinType == JoinRelType.FULL && (isBounded(left) != isBounded(right))) {
throw new IllegalArgumentException("FULL OUTER JOIN unsupported for bounded/unbounded mix; use LEFT OUTER");
} Try / catch
try {
result = sqlEnv.sqlQuery(q).evaluate();
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("FULL OUTER JOIN is not supported")) {
q = rewriteFullOuterToLeftOuterPlusUnion(q);
} else throw e;
} Prevention
- Prefer LEFT/RIGHT OUTER JOIN with the unbounded side on the correct position over FULL OUTER in mixed batch/streaming pipelines
- Determine each input's boundedness (IsBounded) when designing queries
- Model FULL OUTER manually: inner join UNION unmatched-left UNION unmatched-right
When it happens
Trigger: A FULL OUTER JOIN SQL query where one side of the join is bounded (batch/BoundedSource) and the other is unbounded (streaming), causing the planner to select the side-input join implementation.
Common situations: Streaming-batch enrichment queries written as FULL OUTER JOIN; pipelines that switched one input from batch to streaming (or vice versa) after initially working.
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
- Side input join can only be used if one table is bounded.
- Please explicitly specify windowing in SQL query using HOP/T
- CROSS JOIN, JOIN ON FALSE is not supported!
- Operator ${operatorName} is not supported in join condition
- Non equi-join is not supported
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/57e21fba868bf737.
Report an issue: GitHub.