{"record":{"id":"ae6979024be32832","repo":"vitessio/vitess","slug":"unexpected-v","errorCode":null,"errorMessage":"unexpected: %+v","messagePattern":"unexpected: %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vdiff/report.go","lineNumber":84,"sourceCode":"\t// LosslessValues is set when the sample contains all of the row's column\n\t// values without truncation, meaning it can be used to prove that two\n\t// rows are identical during extra-row reconciliation. The marker is\n\t// deliberately affirmative: samples that are lossy (only-pks, truncated\n\t// values) -- or that were persisted by an older binary and reloaded on\n\t// resume -- lack it and are excluded from reconciliation.\n\tLosslessValues bool `json:\"LosslessValues,omitempty\"`\n}\n\nfunc (td *tableDiffer) genRowDiff(queryStmt string, row []sqltypes.Value, opts *tabletmanagerdatapb.VDiffReportOptions) (*RowDiff, error) {\n\trd := &RowDiff{}\n\trd.Row = make(map[string]string)\n\tstatement, err := td.wd.ct.vde.parser.Parse(queryStmt)\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\tif opts.GetDebugQuery() {\n\t\trd.Query = td.genDebugQueryDiff(sel, row, opts.GetOnlyPks())\n\t}\n\n\ttruncated := false\n\taddVal := func(index int, truncateAt int) error {\n\t\tbuf := sqlparser.NewTrackedBuffer(nil)\n\t\tsel.SelectExprs.Exprs[index].Format(buf)\n\t\tcol := buf.String()\n\t\t// Let's truncate if it's really worth it to avoid losing\n\t\t// value for a few chars.\n\t\tif truncateAt > 0 && row[index].Len() >= truncateAt+len(truncatedNotation)+20 {\n\t\t\ttruncated = true\n\t\t\tif row[index].IsBinary() {\n\t\t\t\trb, err := row[index].ToBytes()\n\t\t\t\tif err != nil { // Should never happen","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vdiff/report.go#L66-L102","documentation":"genRowDiff builds the per-row diff query and expects the parsed statement to be a *sqlparser.Select. If the parsed diff statement is any other AST node type (INSERT, UNION, etc.), it fails fast with this error, including the stringified statement.","triggerScenarios":"A vdiff table diff query string, constructed from the workflow's filter rules/table settings, parses to a non-Select statement — typically a malformed or non-SELECT filter rule feeding the table_diff pipeline.","commonSituations":"A MoveTables/Reshard vreplication filter rule that isn't a plain SELECT; manual edits to _vt.vdiff_table or workflow options; a parser version change reinterpreting a rule differently.","solutions":["Inspect the diff query in the vdiff table state (debug output / _vt.vdiff_table) and check it is a plain SELECT.","Fix the workflow's filter/table settings so the source query is a simple SELECT.","Recreate the vdiff after correcting the rule: delete, then VDiff create."],"exampleFix":"// before (filter rule)\nfilter: \"select * from t1 union select * from t2\"\n// after\nfilter: \"select * from t1\" // plain SELECT only","handlingStrategy":"validation","validationCode":"stmt, err := parser.Parse(queryStmt)\nif err != nil { return err }\nif _, ok := stmt.(*sqlparser.Select); !ok {\n  return fmt.Errorf(\"filter rule must be a plain SELECT: %s\", queryStmt)\n}","typeGuard":"func isSelectStatement(stmt sqlparser.Statement) bool {\n  _, ok := stmt.(*sqlparser.Select)\n  return ok\n}","tryCatchPattern":"if err := runDiff(); err != nil && strings.Contains(err.Error(), \"unexpected:\") {\n  // inspect the offending statement printed after 'unexpected:' and fix the filter rule\n}","preventionTips":["Keep vreplication filter rules as simple SELECTs.","Test filter rules with a parser round-trip before creating the workflow.","Don't hand-edit _vt.vdiff_table query columns.","Pin consistent Vitess versions so parser behavior matches."],"tags":["vdiff","sqlparser","internal","assertion"],"backgroundTag":"unexpected-statement-type","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}