vitessio/vitess · error
unsupported subquery: %v
Error message
unsupported subquery: %v
What it means
Subqueries anywhere in a select-list expression are unsupported in vreplication table plans. The sqlparser.Walk rejects *sqlparser.Subquery nodes because the materialization logic cannot evaluate a nested query per row.
Source
Thrown at go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go:528
return nil, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(innerCol))
}
cexpr.operation = opSum
cexpr.expr = innerCol
tpb.addCol(innerCol.Name)
cexpr.references[innerCol.Name.String()] = true
return cexpr, nil
}
}
err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
switch node := node.(type) {
case *sqlparser.ColName:
if !node.Qualifier.IsEmpty() {
return false, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(node))
}
tpb.addCol(node.Name)
cexpr.references[node.Name.String()] = true
case *sqlparser.Subquery:
return false, fmt.Errorf("unsupported subquery: %v", sqlparser.String(node))
case sqlparser.AggrFunc:
return false, fmt.Errorf("unsupported aggregation function: %v", sqlparser.String(node))
}
return true, nil
}, aliased.Expr)
if err != nil {
return nil, err
}
cexpr.expr = aliased.Expr
return cexpr, nil
}
// addCol adds the specified column to the send query
// if it's not already present.
func (tpb *tablePlanBuilder) addCol(ident sqlparser.IdentifierCI) {
tpb.sendSelect.AddSelectExpr(&sqlparser.AliasedExpr{
Expr: &sqlparser.ColName{Name: ident},
})View on GitHub (pinned to 01a25a7d17)
Solutions
- Remove the subquery from the SELECT list.
- Precompute the subquery result into a column (e.g. via a trigger or application logic) and select that column.
- Run the subquery separately against VTGate instead of embedding it in the workflow query.
Example fix
// before select id, (select max(v) from t2) as maxv from t // after select id, maxv from t -- maxv maintained as a stored column
Defensive patterns
Strategy: validation
Validate before calling
// Reject subqueries in the workflow SELECT before submitting
func noSubqueries(sel *sqlparser.Select) bool {
found := false
sqlparser.Walk(func(n sqlparser.SQLNode) (bool, error) {
if _, ok := n.(*sqlparser.Subquery); ok { found = true; return false, nil }
return true, nil
}, sel)
return !found
} Type guard
func isSubquery(n sqlparser.SQLNode) bool { _, ok := n.(*sqlparser.Subquery); return ok } Prevention
- Keep workflow select lists free of nested SELECTs.
- Precompute subquery results into columns or fetch them via separate VTGate queries.
When it happens
Trigger: Materialize/vreplication SELECT containing a subquery, e.g. SELECT (SELECT max(x) FROM t2) AS m FROM t; the walk over aliased.Expr encounters the Subquery node.
Common situations: Porting complex reporting SQL into a materialization workflow; generated queries that embed lookups as scalar subqueries.
Related errors
- only count(*) is supported: %v
- unsupported multiple columns in sum clause: %v
- unsupported non-column name in sum clause: %v
- unsupported aggregation function: %v
- unsupported non-column name or alias in group by clause: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/b523e9ee3f0ba74a.
Report an issue: GitHub.