vitessio/vitess · error
unsupported function: %v
Error message
unsupported function: %v
What it means
The vstreamer plan builder only supports a single aggregate function in a VStreamResults select expression: keyspace_id(). Any other aggregate (COUNT, SUM, MAX, etc.) cannot be computed incrementally from the binlog, so analyzeExpr rejects it with the full SQL text of the aggregate.
Source
Thrown at go/vt/vttablet/tabletserver/vstreamer/planbuilder.go:834
if !ok {
return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(selExpr))
}
switch inner := aliased.Expr.(type) {
case *sqlparser.ColName:
if !inner.Qualifier.IsEmpty() {
return ColExpr{}, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(inner))
}
colnum, err := findColumn(plan.Table, inner.Name)
if err != nil {
return ColExpr{}, err
}
return ColExpr{
ColNum: colnum,
Field: plan.Table.Fields[colnum],
}, nil
case sqlparser.AggrFunc:
if inner.AggrName() != "keyspace_id" {
return ColExpr{}, fmt.Errorf("unsupported function: %v", sqlparser.String(inner))
}
if len(inner.GetArgs()) != 0 {
return ColExpr{}, fmt.Errorf("unexpected: %v", sqlparser.String(inner))
}
cv, err := vschema.FindColVindex(plan.Table.Name)
if err != nil {
return ColExpr{}, err
}
vindexColumns, err := buildVindexColumns(plan.Table, cv.Columns)
if err != nil {
return ColExpr{}, err
}
return ColExpr{
Field: &querypb.Field{
Name: "keyspace_id",
Type: sqltypes.VarBinary,
Charset: collations.CollationBinaryID,
Flags: uint32(querypb.MySqlFlag_BINARY_FLAG),View on GitHub (pinned to 01a25a7d17)
Solutions
- Remove the aggregate from the select list; stream raw columns instead and aggregate client-side.
- If you need the shard's keyspace_id, select only keyspace_id().
- Use a VTGate query (not vstreamer) if you truly need server-side aggregation.
- If you believe the aggregate should be supported, implement it in analyzeExpr's AggrFunc case of planbuilder.go.
Example fix
// before select count(*) from t // after select keyspace_id() from t -- or plain columns select id, name from t
Defensive patterns
Strategy: validation
Validate before calling
// Before calling VStreamResults, ensure every select expr is a plain column or keyspace_id()
func validateVStreamSelect(exprs []string) error {
for _, e := range exprs {
if strings.ContainsAny(e, "(*)") && !strings.EqualFold(strings.TrimSpace(e), "keyspace_id()") {
return fmt.Errorf("aggregate %q not supported; use plain columns or keyspace_id()", e)
}
}
return nil
} Type guard
func isSupportedAggregate(expr string) bool {
return strings.EqualFold(strings.TrimSpace(expr), "keyspace_id()")
} Try / catch
// Go: check the error from analyzeExpr at plan time
if err := plan.AnalyzeExprs(vschema, selExprs); err != nil {
if strings.Contains(err.Error(), "unsupported function") {
return nil, fmt.Errorf("vstream select contains unsupported aggregate, revise select list: %w", err)
}
return nil, err
} Prevention
- Keep vstream select lists to plain columns or keyspace_id()
- Aggregate client-side, never in a VStreamResults query
- Review select lists generated by templates for accidental aggregates
When it happens
Trigger: Calling VStreamResults (or configuring a vstreamer select) with an expression like `select count(*) from t` or `select max(id) from t` — any sqlparser.AggrFunc whose AggrName() is not "keyspace_id".
Common situations: Writing a custom VReplication-style streaming query or materialization flow and accidentally adding a normal SQL aggregate; copying a MySQL query into a vstream select list expecting aggregation to work.
Related errors
- unsupported: %v
- failed to find column name for convert using expression: %v,
- VT03005
- VStreamer is not open
- only integer literals are supported
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/23adaaf4d3139713.
Report an issue: GitHub.