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

  1. Select the vindex column as a plain column reference (no functions/expressions), then do transformations after copy
  2. Compute the value upstream in the source table and select the stored column
  3. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/eb3b9c64f362f762. Report an issue: GitHub.