apache/beam · error · java.lang.UnsupportedOperationException
%s side of an OUTER JOIN must be a non Seekable table.
Error message
%s side of an OUTER JOIN must be a non Seekable table.
What it means
For side-input lookup joins, LEFT OUTER JOIN requires the left (outer) side to be the non-seekable table, and RIGHT OUTER JOIN requires the right side to be non-seekable — the seekable side is broadcast/looked up, and the outer side drives the stream. If the outer side is the seekable table, translation throws this UnsupportedOperationException.
Source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rel/BeamSideInputLookupJoinRel.java:89
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());
BeamRelNode seekableRel =
BeamSqlRelUtils.getBeamRelInput(getInput(seekableInputIndex().get()));
BeamRelNode nonSeekableRel =
BeamSqlRelUtils.getBeamRelInput(getInput(nonSeekableInputIndex().get()));
// Offset field references according to which table is on the left
int factColOffset =View on GitHub (pinned to 12126d8942)
Solutions
- Swap the join operands so the non-seekable table is on the OUTER side: RIGHT OUTER JOIN with the seekable table on the left, or LEFT OUTER JOIN with it on the right.
- Verify which input is Seekable (seekableInputIndex) and orient the outer join accordingly.
- Use an INNER JOIN, which has no outer-side orientation requirement, if unmatched rows aren't needed.
- Fall back to a standard join (non side-input-lookup) by making the lookup table a regular bounded input.
Example fix
-- before SELECT * FROM seekable_table LEFT OUTER JOIN stream_table ON seekable_table.k = stream_table.k -- after SELECT * FROM stream_table RIGHT OUTER JOIN seekable_table ON stream_table.k = seekable_table.k
Defensive patterns
Strategy: validation
Validate before calling
if ((joinType == JoinRelType.LEFT && seekableIndex == 0) || (joinType == JoinRelType.RIGHT && seekableIndex == 1)) { throw new IllegalArgumentException("Outer side must be the non-Seekable table"); } Type guard
boolean orientationOk = joinType != JoinRelType.LEFT || !isSeekable(left) && joinType != JoinRelType.RIGHT || !isSeekable(right);
Try / catch
try { pipeline.apply(SqlTransform.query(sql)); } catch (UnsupportedOperationException e) { if (e.getMessage().contains("must be a non Seekable table")) { /* swap join operands */ } else { throw e; } } Prevention
- Always place the non-seekable (streaming) table on the OUTER side of LEFT/RIGHT joins
- Determine SeekableTable registration order before authoring the query
- Use INNER JOIN to sidestep orientation constraints
- Add a startup-time boundedness/seekability assertion in pipeline construction
When it happens
Trigger: BeamSideInputLookupJoinRel.buildPTransform sees joinType==LEFT with seekableInputIndex()==0 (left side seekable), or joinType==RIGHT with seekableInputIndex()==1 (right side seekable).
Common situations: Writing 'SELECT ... FROM seekable_table LEFT OUTER JOIN streaming_table ...' when the rule expects the reverse orientation; users often don't know which table is registered as Seekable.
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
- FULL OUTER JOIN is not supported when join a 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/db49769946d401c4.
Report an issue: GitHub.