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

  1. Ensure every non-trivial expression in the workflow select/rule has an explicit `AS alias` so it maps to a target column name
  2. Simplify the vdiff/migration filter rules to select plain columns; run the diff on base columns instead of computed expressions
  3. If a new sqlparser expression type is legitimately needed, extend the switch in getColumnNameForSelectExpr to handle it and regenerate/rebuild
  4. 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

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


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