vitessio/vitess · error

unsupported select expression: %v

Error message

unsupported select expression: %v

What it means

matchColInSelect walks the select expressions of a workflow source query and only supports StarExpr and simple AliasedExpr column references. Any other expression type (subqueries, literals, function calls without alias handling, etc.) hits the default branch and is rejected with this error. It is a deliberate limitation of the query-rewrite-rule generator.

Source

Thrown at go/vt/vtctl/workflow/utils.go:320

		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 shouldInclude(table string, excludes []string) bool {
	// We filter out internal tables elsewhere when processing SchemaDefinition
	// structures built from the GetSchema database related API calls. In this
	// case, however, the table list comes from the user via the -tables flag
	// so we need to filter out internal table names here in case a user has
	// explicitly specified some.
	// This could happen if there's some automated tooling that creates the list of
	// tables to explicitly specify.
	// But given that this should never be done in practice, we ignore the request.
	if schema.IsInternalOperationTableName(table) {
		return false
	}
	return !slices.Contains(excludes, table)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Replace the unsupported select expression with a plain column or `select <cols> from <table>` list.
  2. Use `select *` or an explicit column list limited to the columns the workflow needs (including the vindex columns).
  3. Split complex queries out of the workflow definition; workflows copy tables, they do not run arbitrary queries.

Example fix

// before
rule := "select count(*) from t"
// error: unsupported select expression: count(*)
// after
rule := "select col1, col2 from t"
Defensive patterns

Strategy: validation

Validate before calling

// keep workflow select lists to StarExpr or column refs only
re := regexp.MustCompile(`(?i)\b(count|sum|avg|min|max)\s*\(|\(\s*select\b`)
if re.MatchString(rule) {
    return fmt.Errorf("workflow select must not contain expressions: %s", rule)
}

Type guard

func isSupportedSelectExpr(e sqlparser.SelectExpr) bool {
    switch e.(type) {
    case *sqlparser.StarExpr:
        return true
    case *sqlparser.AliasedExpr:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: A workflow (MoveTables/Reshard) filter or rule select contains an unsupported expression type in the select list — e.g. `select count(*) from t`, a scalar subquery, or a bare literal — and generateRule calls matchColInSelect to locate a vindex column there.

Common situations: Copy-pasting analytical SELECT queries into migration/reshard filter rules; auto-generated rules containing aggregates; older configs written for other tools being reused with vitess workflows.

Related errors


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