apache/beam · error · java.lang.UnsupportedOperationException
FULL OUTER JOIN is not supported when join a Seekable table
Error message
FULL OUTER JOIN is not supported when join a Seekable table with a non Seekable table.
What it means
Beam SQL's side-input lookup join supports only INNER, LEFT OUTER (non-seekable on the left) and RIGHT OUTER (non-seekable on the right) joins between a Seekable table and a non-Seekable table. A FULL OUTER JOIN cannot be performed this way because it would require streaming the seekable side's unmatched rows, so the translation throws this UnsupportedOperationException.
Source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rel/BeamSideInputLookupJoinRel.java:82
RelOptCluster cluster,
RelTraitSet traitSet,
RelNode left,
RelNode right,
RexNode condition,
Set<CorrelationId> variablesSet,
JoinRelType joinType) {
super(cluster, traitSet, left, right, condition, variablesSet, joinType);
}
@Override
public PTransform<PCollectionList<Row>, PCollection<Row>> buildPTransform() {
// if one of the sides is Seekable & the other is non Seekable
// then do a sideInputLookup join.
// When doing a sideInputLookup join, the windowFn does not need to match.
// Only support INNER JOIN & LEFT OUTER JOIN where left side of the join must be
// non Seekable & RIGHT OUTER JOIN where right side of the join must be non Seekable
if (joinType == JoinRelType.FULL) {
throw new UnsupportedOperationException(
"FULL OUTER JOIN is not supported when join "
+ "a Seekable table with a non Seekable table.");
}
if ((joinType == JoinRelType.LEFT && seekableInputIndex().get() == 0)
|| (joinType == JoinRelType.RIGHT && seekableInputIndex().get() == 1)) {
throw new UnsupportedOperationException(
String.format("%s side of an OUTER JOIN must be a non Seekable table.", joinType.name()));
}
return new SideInputLookupJoin();
}
private class SideInputLookupJoin extends PTransform<PCollectionList<Row>, PCollection<Row>> {
@Override
public PCollection<Row> expand(PCollectionList<Row> pinput) {
Schema schema = CalciteUtils.toSchema(getRowType());
View on GitHub (pinned to 12126d8942)
Solutions
- Rewrite as LEFT OUTER JOIN with the non-seekable table on the left, plus a complementary RIGHT-OUTER-derived query for unmatched seekable rows, and UNION ALL the results.
- Change the join type to INNER or LEFT/RIGHT OUTER, whichever matches which side is seekable.
- Materialize the seekable table as a bounded PCollection and use a regular (non-lookup) join that supports FULL OUTER JOIN.
- Implement a custom join transform (e.g. CoGroupByKey-based) if FULL OUTER semantics over both sides are truly required.
Example fix
-- before SELECT * FROM non_seekable FULL OUTER JOIN seekable_table ON non_seekable.k = seekable_table.k -- after SELECT * FROM non_seekable LEFT OUTER JOIN seekable_table ON non_seekable.k = seekable_table.k
Defensive patterns
Strategy: validation
Validate before calling
if (joinType == JoinRelType.FULL && (isSeekable(left) ^ isSeekable(right))) { throw new IllegalArgumentException("FULL OUTER JOIN unsupported for mixed Seekable/non-Seekable sides"); } Type guard
boolean lookupJoinAllowed = !(joinType == JoinRelType.FULL && exactlyOneSeekable);
Try / catch
try { pipeline.apply(SqlTransform.query(sql)); } catch (UnsupportedOperationException e) { if (e.getMessage().contains("FULL OUTER JOIN is not supported")) { /* decompose into LEFT OUTER + anti-join UNION ALL */ } else { throw e; } } Prevention
- Avoid FULL OUTER JOIN when one side is a SeekableTable
- Decompose FULL OUTER into LEFT OUTER plus complementary anti-join
- Know which of your tables are registered as Seekable before writing join SQL
- Materialize seekable lookup tables as bounded PCollections when full outer semantics are needed
When it happens
Trigger: Translating a BeamSql FULL OUTER JOIN query where exactly one side is a SeekableTable and the side-input lookup join rule (BeamSideInputLookupJoinRel) is chosen.
Common situations: Attempting FULL OUTER JOIN against a seekable side-input table such as a lookup backed by a stateful/seekable DoFn (e.g. a JDBC or BigTable-backed SeekableTable) in a streaming pipeline.
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
- %s side of an OUTER JOIN must be a non Seekable table.
- FULL OUTER JOIN is not supported when join a bounded table w
- %s side of an OUTER JOIN must be Unbounded table.
- Side input join can only be used if one table is bounded.
- Please explicitly specify windowing in SQL query using HOP/T
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/769142b0478e80e4.
Report an issue: GitHub.