apache/druid · error · IllegalArgumentException
Cannot build hash-join matcher on non-key-based condition: %
Error message
Cannot build hash-join matcher on non-key-based condition: %s
What it means
Hash-join matching relies on the right-hand join column being one of the table's key columns, because only key columns have usable indexes for lookups. getIndex() validates the condition's right column is a key column and throws IAE otherwise.
Source
Thrown at processing/src/main/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcher.java:148
this.selectorFactory = selectorFactory != null
? selectorFactory
: new IndexedTableColumnSelectorFactory(table, () -> currentRow, closer);
if (remainderNeeded) {
this.matchedRows = new IntRBTreeSet();
} else {
this.matchedRows = null;
}
}
private static IndexedTable.Index getIndex(
final IndexedTable table,
final Equality condition
)
{
if (!table.keyColumns().contains(condition.getRightColumn())) {
throw new IAE("Cannot build hash-join matcher on non-key-based condition: %s", condition);
}
final int keyColumnNumber = table.rowSignature().indexOf(condition.getRightColumn());
return table.columnIndex(keyColumnNumber);
}
private static ConditionMatcher makeConditionMatcher(
final IndexedTable.Index index,
final ColumnSelectorFactory selectorFactory,
final Equality condition
)
{
return ColumnProcessors.makeProcessor(
condition.getLeftExpr(),
index.keyType(),
new ConditionMatcherFactory(index, condition.isIncludeNull()),
selectorFactoryView on GitHub (pinned to 9b90983fd2)
Solutions
- Include the join column in the keyColumns list when building the IndexedTable (e.g. RowBasedIndexedTable builder .keyColumns(...))
- Rewrite the query so the join condition uses a column that is a declared key
- Verify table.keyColumns() covers all columns used on the right side of ON equalities
Example fix
// before
RowBasedIndexedTable.Builder.create(adapter, signature, "v1")
.keyColumns(Set.of("id")).build(rows, keyColumnsCacheKey);
// after
RowBasedIndexedTable.Builder.create(adapter, signature, "v1")
.keyColumns(Set.of("id", "joinKey")).build(rows, keyColumnsCacheKey); Defensive patterns
Strategy: validation
Validate before calling
if (!table.keyColumns().contains(rightColumn)) { throw new IllegalArgumentException("join column must be a key column: " + rightColumn); } Try / catch
try { matcher = new IndexedTableJoinMatcher(...); } catch (IAE e) { /* re-plan or add key column */ } Prevention
- Declare every expected join column as a key column at table build time
- Check table.keyColumns() coverage before planning joins
When it happens
Trigger: Building an IndexedTableJoinMatcher where the Equality condition's right column (the table-side column) is not in table.keyColumns(), e.g. joining ON t1.a = table.nonKeyColumn.
Common situations: Query referencing a broadcast table column that was not declared as a key column when the IndexedTable was built; tables built without indexes on the join key; schema drift between the table definition and the query.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Column[%d] is not a valid column for segment[%s]
- Column[%d] is not a valid column for the frame based datasou
- Index[%s] < 0
- Index[%d] >= size[%d]
- Index[%s] < 0
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/b8cb853a6f456583.
Report an issue: GitHub.