apache/beam · error · java.lang.UnsupportedOperationException
Cannot get column index from ${type}
Error message
Cannot get column index from ${type} What it means
getColumnIndex resolves a join-key operand to an input column index, supporting RexInputRef and RexFieldAccess (recursive). Any other RexNode kind, or an operand whose type cannot be resolved to a column, triggers UnsupportedOperationException with the node's type in the message.
Source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rel/BeamJoinRel.java:223
}
}
// Only support {RexInputRef | RexFieldAccess} = {RexInputRef | RexFieldAccess}
private static boolean isIllegalJoinConjunctionClause(RexCall rexCall) {
return (!(rexCall.getOperands().get(0) instanceof RexInputRef)
&& !(rexCall.getOperands().get(0) instanceof RexFieldAccess))
|| (!(rexCall.getOperands().get(1) instanceof RexInputRef)
&& !(rexCall.getOperands().get(1) instanceof RexFieldAccess));
}
private static int getColumnIndex(RexNode rexNode) {
if (rexNode instanceof RexInputRef) {
return ((RexInputRef) rexNode).getIndex();
} else if (rexNode instanceof RexFieldAccess) {
return getColumnIndex(((RexFieldAccess) rexNode).getReferenceExpr());
}
throw new UnsupportedOperationException("Cannot get column index from " + rexNode.getType());
}
/**
* This method returns the Boundedness of a RelNode. It is used during planning and applying
* {@link org.apache.beam.sdk.extensions.sql.impl.rule.BeamCoGBKJoinRule} and {@link
* org.apache.beam.sdk.extensions.sql.impl.rule.BeamSideInputJoinRule}
*
* <p>The Volcano planner works in a top-down fashion. It starts by transforming the root and move
* towards the leafs of the plan. Due to this when transforming a logical join its inputs are
* still in the logical convention. So, Recursively visit the inputs of the RelNode till
* BeamIOSourceRel is encountered and propagate the boundedness upwards.
*
* <p>The Boundedness of each child of a RelNode is stored in a list. If any of the children are
* Unbounded, the RelNode is Unbounded. Else, the RelNode is Bounded.
*
* @param relNode the RelNode whose Boundedness has to be determined
* @return {@code PCollection.isBounded}
*/View on GitHub (pinned to 12126d8942)
Solutions
- Ensure both sides of each '=' conjunct are plain column references or struct field accesses
- Precompute derived join keys in a subquery/CTE so the join sees bare columns
- If extending Beam, add handling for additional RexNode kinds (e.g. RexCall with deterministic functions) in getColumnIndex
Example fix
// before SELECT * FROM a JOIN b ON a.id + 1 = b.id; // after SELECT * FROM (SELECT id + 1 AS id_next FROM a) a JOIN b ON a.id_next = b.id;
Defensive patterns
Strategy: type-guard
Validate before calling
// Check join-key operands resolve to plain columns before building the query
boolean isPlainColumnOrField(String expr) {
return expr.matches("\\w+") || expr.matches("\\w+(\\.\\w+)+"); // no function calls/casts/arithmetic
} Type guard
static boolean isResolvableJoinKey(RexNode node) {
return node instanceof RexInputRef
|| (node instanceof RexFieldAccess
&& isResolvableJoinKey(((RexFieldAccess) node).getReferenceExpr()));
} Try / catch
try {
result = sqlEnv.sqlQuery(q).evaluate();
} catch (UnsupportedOperationException e) {
if (e.getMessage().startsWith("Cannot get column index from")) {
q = projectJoinKeysFirst(q);
} else throw e;
} Prevention
- Use bare column references as join keys
- Compute derived keys in a preceding projection
- Recursively validate struct-field join keys match what getColumnIndex supports
When it happens
Trigger: A join predicate operand that is neither a plain column reference nor a struct field access — literals, RexCall expressions, or nested unsupported field-access shapes — passed into getColumnIndex from extractJoinPairOfRexNodes.
Common situations: Joining on expressions (concat, casts, arithmetic) or constants inside the ON clause; struct field access patterns deeper than what getColumnIndex recurses into.
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
- CROSS JOIN, JOIN ON FALSE is not supported!
- Operator ${operatorName} is not supported in join condition
- Non equi-join is not supported
- Only support column reference or struct field access in conj
- FULL OUTER JOIN is not supported when join a bounded table w
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/a6672c7a1226882c.
Report an issue: GitHub.