prestodb/presto · error · SemanticException
MISSING_ATTRIBUTE
MISSING_ATTRIBUTE
Error message
Column '%s' is missing from left side of join
What it means
In a USING-join, every listed column must be resolvable on both sides of the join. If the column cannot be resolved as a field of the left relation, analysis throws MISSING_ATTRIBUTE naming the column. (A companion error reports the same for the right side.)
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java:3958
private Scope analyzeJoinUsing(Join node, List<Identifier> columns, Optional<Scope> scope, Scope left, Scope right)
{
List<Field> joinFields = new ArrayList<>();
List<Integer> leftJoinFields = new ArrayList<>();
List<Integer> rightJoinFields = new ArrayList<>();
Set<Identifier> seen = new HashSet<>();
for (Identifier column : columns) {
if (!seen.add(column)) {
throw new SemanticException(DUPLICATE_COLUMN_NAME, column, "Column '%s' appears multiple times in USING clause", column.getValue());
}
Optional<ResolvedField> leftField = left.tryResolveField(column);
Optional<ResolvedField> rightField = right.tryResolveField(column);
if (!leftField.isPresent()) {
throw new SemanticException(MISSING_ATTRIBUTE, column, "Column '%s' is missing from left side of join", column.getValue());
}
if (!rightField.isPresent()) {
throw new SemanticException(MISSING_ATTRIBUTE, column, "Column '%s' is missing from right side of join", column.getValue());
}
// ensure a comparison operator exists for the given types (applying coercions if necessary)
try {
functionAndTypeResolver.resolveOperator(OperatorType.EQUAL, fromTypes(
leftField.get().getType(), rightField.get().getType()));
}
catch (OperatorNotFoundException e) {
throw new SemanticException(TYPE_MISMATCH, column, "%s", e.getMessage());
}
Optional<Type> type = functionAndTypeResolver.getCommonSuperType(leftField.get().getType(), rightField.get().getType());
analysis.addTypes(ImmutableMap.of(NodeRef.of(column), type.get()));
joinFields.add(Field.newUnqualified(column.getLocation(), column.getValue(), type.get()));View on GitHub (pinned to 55bb57d202)
Solutions
- Verify the column exists on both relations via SHOW COLUMNS and fix the name or the USING list
- Swap the join operands if the column genuinely lives on the other side
- Rewrite with an explicit ON a.col = b.col if the column exists on only one side plus a coalesce/literal for the other
- Qualify with subselects/aliases that project the needed column into both relations before the USING join
Example fix
// before SELECT * FROM orders o JOIN customers c USING (customer_id) -- customers has no customer_id // after SELECT * FROM orders o JOIN customers c ON o.customer_id = c.id
Defensive patterns
Strategy: validation
Validate before calling
SHOW COLUMNS FROM left_relation; -- confirm the USING column exists here (and on the right side too)
Prevention
- Confirm join keys exist on both relations before USING
- Prefer explicit ON clauses when sides are asymmetric
- Use schema-aware autocomplete and qualify relation order deliberately
When it happens
Trigger: `SELECT ... FROM a JOIN b USING (x)` where relation a has no column x (typo, wrong join order, column only exists on one side).
Common situations: Swapped table order relative to the column availability; column renamed in one relation; typos; building USING lists from a schema that doesn't match the actual query.
Related errors
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/99f6b0c3067fcce5.
Report an issue: GitHub.