vitessio/vitess · error
vindex column cannot be a complex expression: %v
Error message
vindex column cannot be a complex expression: %v
What it means
generateInserts must locate each primary-vindex column in the SourceExpression's SELECT list to build INSERT statements. matchColInSelect found the matching select expression, but it is not a simple column reference (it is a computed expression like CONCAT(name), lower(email), or a function call), so the vindex value cannot be mapped and the error is returned.
Source
Thrown at go/vt/wrangler/materializer.go:1489
func matchColInSelect(col sqlparser.IdentifierCI, sel *sqlparser.Select) (*sqlparser.ColName, error) {
for _, selExpr := range sel.GetColumns() {
switch selExpr := selExpr.(type) {
case *sqlparser.StarExpr:
return &sqlparser.ColName{Name: col}, nil
case *sqlparser.AliasedExpr:
match := selExpr.As
if match.IsEmpty() {
if colExpr, ok := selExpr.Expr.(*sqlparser.ColName); ok {
match = colExpr.Name
} else {
// Cannot match against a complex expression.
continue
}
}
if match.Equal(col) {
colExpr, ok := selExpr.Expr.(*sqlparser.ColName)
if !ok {
return nil, fmt.Errorf("vindex column cannot be a complex expression: %v", sqlparser.String(selExpr))
}
return colExpr, nil
}
default:
return nil, fmt.Errorf("unsupported select expression: %v", sqlparser.String(selExpr))
}
}
return nil, fmt.Errorf("could not find vindex column %v", sqlparser.String(col))
}
func (mz *materializer) createStreams(ctx context.Context, insertsMap map[string]string) error {
return mz.forAllTargets(func(target *topo.ShardInfo) error {
inserts := insertsMap[target.ShardName()]
targetPrimary, err := mz.wr.ts.GetTablet(ctx, target.PrimaryAlias)
if err != nil {
return vterrors.Wrapf(err, "GetTablet(%v) failed", target.PrimaryAlias)
}
buf := &strings.Builder{}View on GitHub (pinned to 01a25a7d17)
Solutions
- Select the vindex column as a plain column reference (no functions/expressions), then do transformations after copy
- Compute the value upstream in the source table and select the stored column
- Materialize into an unsharded or reference table first, then transform
Example fix
// before
{"sourceExpression":"select concat(first,' ',last) as name from users"} // name is primary vindex
// after
{"sourceExpression":"select first, last, name from users"} Defensive patterns
Strategy: validation
Validate before calling
for _, vcol := range primaryVindexColumns {
sel, _ := parser.Parse(sourceExpr)
if _, err := findVindexColInSelect(sel.(*sqlparser.Select), sqlparser.NewColName(vcol)); err != nil {
return fmt.Errorf("vindex column %s must be a plain column in SourceExpression", vcol)
}
} Prevention
- Never wrap primary vindex columns in functions or expressions in copy filters
- Select vindex columns verbatim from the source table
- Do transformations post-copy, not in the filter
When it happens
Trigger: SourceExpression selects an expression (function/arithmetical) for a column that is the target table's primary vindex column, e.g. `select concat(first,' ',last) as name from users` where `name` is the vindex column.
Common situations: Materializing a sharded table while transforming the vindex column in the SELECT; renaming computed columns with aliases that collide with vindex column names.
Related errors
- could not find vindex column %v
- source and target table names must match for copying schema:
- unrecognized statement: %s
- unsupported select expression: %v
- one or two tables must be specified
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/eb3b9c64f362f762.
Report an issue: GitHub.