{"record":{"id":"99e8f9fd5ee97fd6","repo":"vitessio/vitess","slug":"unexpected-v-99e8f9","errorCode":null,"errorMessage":"unexpected: %v","messagePattern":"unexpected: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vdiff/table_plan.go","lineNumber":83,"sourceCode":"\ttable          *tabletmanagerdatapb.TableDefinition\n\torderBy        sqlparser.OrderBy\n\taggregates     []*engine.AggregateParams\n\tWorkflowConfig **vttablet.VReplicationConfig\n}\n\nfunc (td *tableDiffer) buildTablePlan(dbClient binlogplayer.DBClient, dbName string, collationEnv *collations.Environment) (*tablePlan, error) {\n\ttp := &tablePlan{\n\t\ttable:          td.table,\n\t\tdbName:         dbName,\n\t\tWorkflowConfig: td.wd.WorkflowConfig,\n\t}\n\tstatement, err := td.wd.ct.vde.parser.Parse(td.sourceQuery)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsel, ok := statement.(*sqlparser.Select)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected: %v\", sqlparser.String(statement))\n\t}\n\n\tsourceSelect := &sqlparser.Select{}\n\ttargetSelect := &sqlparser.Select{}\n\t// Aggregates is the list of Aggregate functions, if any.\n\tvar aggregates []*engine.AggregateParams\n\tfor _, selExpr := range sel.GetColumns() {\n\t\tswitch selExpr := selExpr.(type) {\n\t\tcase *sqlparser.StarExpr:\n\t\t\t// If it's a '*' expression, expand column list from the schema.\n\t\t\tfor _, fld := range tp.table.Fields {\n\t\t\t\taliased := &sqlparser.AliasedExpr{Expr: &sqlparser.ColName{Name: sqlparser.NewIdentifierCI(fld.Name)}}\n\t\t\t\tsourceSelect.AddSelectExpr(aliased)\n\t\t\t\ttargetSelect.AddSelectExpr(aliased)\n\t\t\t}\n\t\tcase *sqlparser.AliasedExpr:\n\t\t\tvar targetCol *sqlparser.ColName\n\t\t\tif selExpr.As.IsEmpty() {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vdiff/table_plan.go#L65-L101","documentation":"buildTablePlan parses the source query of a vreplication rule and requires it to be a plain SELECT statement, since vdiff builds source/target selects from it. If the parsed statement is any other AST node type (INSERT, UPDATE, SET, etc.), it fails with `unexpected: <sql>`.","triggerScenarios":"A binlog filter rule's Filter value, when parsed by sqlparser, is not a *sqlparser.Select — e.g. the rule was written as a full non-select statement or contains multiple/invalid statements.","commonSituations":"Hand-edited vreplication filter rules (e.g. in the _vt.vreplication workflow column or MoveTables rules) that accidentally contain non-SELECT text; copying a rule from another tool; version differences in the filter stored for legacy workflows.","solutions":["Inspect the workflow's filter rules and fix the offending rule to be a single valid SELECT statement","If the rule was meant to be a keyrange/table filter, use the supported forms (table name, keyrange string, or SELECT) instead of arbitrary SQL","Re-create the workflow (MoveTables/Migrate) with correct filter rules rather than editing stored SQL by hand"],"exampleFix":"// before (invalid filter rule)\nrule.Filter = \"update t set a=1\"\n// after\nrule.Filter = \"select * from t\"","handlingStrategy":"validation","validationCode":"stmt, err := parser.Parse(rule.Filter)\nif err != nil { return err }\nif _, ok := stmt.(*sqlparser.Select); !ok {\n  return fmt.Errorf(\"filter rule must be a SELECT: %s\", rule.Filter)\n}","typeGuard":"func isSelectStatement(sqlText string) bool {\n  stmt, err := sqlparser.Parse(sqlText)\n  if err != nil { return false }\n  _, ok := stmt.(*sqlparser.Select)\n  return ok\n}","tryCatchPattern":"td, err := buildTablePlan(...)\nif err != nil {\n  if strings.Contains(err.Error(), \"unexpected:\") {\n    log.Errorf(\"filter rule for %s is not a SELECT; fix the rule\", tableName)\n  }\n  return err\n}","preventionTips":["Never hand-edit stored filter rules to non-SELECT SQL","Use supported filter forms: table name, keyrange, or SELECT","Test new workflows' rules with vdiff show/plan before production runs"],"tags":["vdiff","sqlparser","filter-rules"],"backgroundTag":"vdiff-invalid-filter-rule","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}