vitessio/vitess · error
found target SelectExpr which was neither ColName nor FuncEx
Error message
found target SelectExpr which was neither ColName nor FuncExpr: %+v
What it means
During VDiff table plan construction, getColumnNameForSelectExpr derives the column name for each target SELECT expression. Only plain column references (ColName) and function expressions with an alias (e.g. convert_tz() results) are supported; any other SelectExpr shape throws this error.
Source
Thrown at go/vt/vttablet/tabletmanager/vdiff/table_differ.go:1071
if _, ok := sourcePKColumns[pkc]; ok {
td.tablePlan.sourcePkCols = append(td.tablePlan.sourcePkCols, i)
}
}
return nil
}
func getColumnNameForSelectExpr(selectExpression sqlparser.SelectExpr) (string, error) {
aliasedExpr := selectExpression.(*sqlparser.AliasedExpr)
expr := aliasedExpr.Expr
var colname string
switch t := expr.(type) {
case *sqlparser.ColName:
colname = t.Name.Lowered()
case *sqlparser.FuncExpr: // only in case datetime was converted using convert_tz()
colname = aliasedExpr.As.Lowered()
default:
return "", fmt.Errorf("found target SelectExpr which was neither ColName nor FuncExpr: %+v", aliasedExpr)
}
return colname, nil
}
View on GitHub (pinned to 01a25a7d17)
Solutions
- Ensure every non-trivial expression in the workflow select/rule has an explicit `AS alias` so it maps to a target column name
- Simplify the vdiff/migration filter rules to select plain columns; run the diff on base columns instead of computed expressions
- If a new sqlparser expression type is legitimately needed, extend the switch in getColumnNameForSelectExpr to handle it and regenerate/rebuild
- Verify source and target schemas match for the table so the target select list is regenerated as plain ColNames
Example fix
// before (filter rule with computed expr, no alias) select id, price * quantity from orders // after select id, (price * quantity) as line_total from orders
Defensive patterns
Strategy: validation
Validate before calling
// before starting vdiff, verify each selected expression is a plain column or an aliased function
for _, expr := range selectExprs {
ae, ok := expr.(*sqlparser.AliasedExpr)
if !ok { return fmt.Errorf("unsupported select expr") }
switch ae.Expr.(type) {
case *sqlparser.ColName:
case *sqlparser.FuncExpr:
if ae.As.IsEmpty() { return fmt.Errorf("func expr needs alias") }
default:
return fmt.Errorf("unsupported expression type in select list")
}
} Type guard
func isSimpleSelectExpr(e sqlparser.SelectExpr) bool {
ae, ok := e.(*sqlparser.AliasedExpr)
if !ok { return false }
switch ae.Expr.(type) {
case *sqlparser.ColName:
return true
case *sqlparser.FuncExpr:
return !ae.As.IsEmpty()
}
return false
} Try / catch
colname, err := getColumnNameForSelectExpr(expr)
if err != nil {
return fmt.Errorf("table %s has unsupported target select expr: %w", tableName, err)
} Prevention
- Keep vreplication filter rules to plain column selects
- Always alias computed expressions (convert_tz etc.)
- Diff base columns, not derived values
- Validate rules with sqlparser before saving the workflow
When it happens
Trigger: The target select list for a table contains an expression that is neither a bare column name nor a (aliased) FuncExpr — e.g. a subquery, CASE expression, arithmetic like (a+b), CastExpr, or a FuncExpr missing an As alias when getColumnNameForSelectExpr reaches the FuncExpr path with empty As.
Common situations: Running VDiff after the workflow's filter/rule select list was hand-edited to include computed columns; MoveTables with a custom keyrange filter producing unusual select expressions; schema drifted between source and target so the reconstructed target select no longer matches expectations.
Related errors
- unexpected: %+v
- unexpected: %v
- expression needs an alias: %v
- table expression is complex
- VDiff not implemented in vtcombo
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/4220bacbb8c367bf.
Report an issue: GitHub.