vitessio/vitess · error

unsupported non-column name or alias in group by clause: %v

Error message

unsupported non-column name or alias in group by clause: %v

What it means

GROUP BY in a vreplication table plan may only reference columns by name (a *sqlparser.ColName). Arbitrary expressions, literals, or positional references in GROUP BY are rejected because the builder resolves each group-by item against select-list aliases via findCol.

Source

Thrown at go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go:557

}

// addCol adds the specified column to the send query
// if it's not already present.
func (tpb *tablePlanBuilder) addCol(ident sqlparser.IdentifierCI) {
	tpb.sendSelect.AddSelectExpr(&sqlparser.AliasedExpr{
		Expr: &sqlparser.ColName{Name: ident},
	})
}

func (tpb *tablePlanBuilder) analyzeGroupBy(groupBy *sqlparser.GroupBy) error {
	if groupBy == nil {
		// If there's no grouping, the it's an insertNormal.
		return nil
	}
	for _, expr := range groupBy.Exprs {
		colname, ok := expr.(*sqlparser.ColName)
		if !ok {
			return fmt.Errorf("unsupported non-column name or alias in group by clause: %v", sqlparser.String(expr))
		}
		cexpr := tpb.findCol(colname.Name)
		if cexpr == nil {
			return fmt.Errorf("group by expression does not reference an alias in the select list: %v", sqlparser.String(expr))
		}
		if cexpr.operation != opExpr {
			return fmt.Errorf("group by expression is not allowed to reference an aggregate expression: %v", sqlparser.String(expr))
		}
		cexpr.isGrouped = true
	}
	// If all colExprs are grouped, then it's an insertIgnore.
	tpb.onInsert = insertIgnore
	for _, cExpr := range tpb.colExprs {
		if !cExpr.isGrouped {
			// If some colExprs are not grouped, then it's an insertOnDup.
			tpb.onInsert = insertOnDup
			break
		}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Group only by a column name that also appears (aliased) in the SELECT list.
  2. Create an aliased select item for the computed value first, then GROUP BY that alias: SELECT UPPER(name) AS uname ... GROUP BY uname.
  3. Remove numeric positional group-by items and use explicit column names.

Example fix

// before
select upper(name) from t group by 1
// after
select upper(name) as uname from t group by uname
Defensive patterns

Strategy: validation

Validate before calling

// Require every GROUP BY item to be a plain column name
func validGroupBy(sel *sqlparser.Select) bool {
    for _, e := range sel.GroupBy.Exprs {
        if _, ok := e.(*sqlparser.ColName); !ok { return false }
    }
    return true
}

Type guard

func isGroupableCol(n sqlparser.SQLNode) bool { _, ok := n.(*sqlparser.ColName); return ok }

Prevention

When it happens

Trigger: Materialize/vreplication SELECT with GROUP BY <expr>, e.g. GROUP BY UPPER(name), GROUP BY 1, or GROUP BY a+b; analyzeGroupBy's type assertion to *sqlparser.ColName fails.

Common situations: Queries copied from engines supporting GROUP BY expressions/positions; users grouping by computed values without aliasing them in the select list.

Related errors


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