{"record":{"id":"6062e3726aaebcb1","repo":"vitessio/vitess","slug":"rule-v-does-not-have-a-select-expression-in-vrepl","errorCode":null,"errorMessage":"rule %v does not have a select expression in vreplication","messagePattern":"rule (.+?) does not have a select expression in vreplication","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/workflow/stream_migrator.go","lineNumber":1124,"sourceCode":"\n\treturn shardedStreams, nil\n}\n\n// templatizeRule replaces keyrange values with {{.}}.\n// This can then be used by go's template package to substitute other keyrange values.\nfunc (sm *StreamMigrator) templatizeRule(ctx context.Context, rule *binlogdatapb.Rule) (StreamType, error) {\n\tvtable, ok := sm.ts.SourceKeyspaceSchema().Tables[rule.Match]\n\tif !ok && !schema.IsInternalOperationTableName(rule.Match) {\n\t\treturn StreamTypeUnknown, fmt.Errorf(\"table %v not found in vschema\", rule.Match)\n\t}\n\n\tif vtable != nil && vtable.Type == vindexes.TypeReference {\n\t\treturn StreamTypeReference, nil\n\t}\n\n\tswitch {\n\tcase rule.Filter == \"\":\n\t\treturn StreamTypeUnknown, fmt.Errorf(\"rule %v does not have a select expression in vreplication\", rule)\n\tcase key.IsValidKeyRange(rule.Filter):\n\t\trule.Filter = \"{{.}}\"\n\t\treturn StreamTypeSharded, nil\n\tcase rule.Filter == vreplication.ExcludeStr:\n\t\treturn StreamTypeUnknown, fmt.Errorf(\"unexpected rule in vreplication: %v\", rule)\n\tdefault:\n\t\tif err := sm.templatizeKeyRange(ctx, rule); err != nil {\n\t\t\treturn StreamTypeUnknown, err\n\t\t}\n\n\t\treturn StreamTypeSharded, nil\n\t}\n}\n\nfunc (sm *StreamMigrator) templatizeKeyRange(ctx context.Context, rule *binlogdatapb.Rule) error {\n\tstatement, err := sm.parser.Parse(rule.Filter)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":1106,"sourceCodeEnd":1142,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/workflow/stream_migrator.go#L1106-L1142","documentation":"After classifying a rule's table, templatizeRule inspects rule.Filter to templatize its keyrange or SELECT expression. If the filter is an empty string there is no select expression to work with, so the rule cannot be migrated and this error is thrown. A vreplication rule must carry either a keyrange or a select expression as its filter.","triggerScenarios":"templatize -> templatizeRule encountering a Rule whose Filter field is \"\" — e.g. a manually inserted/edited _vt.vreplication row or a filter rule constructed programmatically without a filter, then a stream migration (BuildStreamMigrator/StopStreams) runs.","commonSituations":"Hand-edited _vt.vreplication rows; custom tooling that wrote filter rules with an empty filter; workflow created by an older Vitess version writing rules in a format the current code rejects; corrupted binlog source proto.","solutions":["Inspect the stream's filter (`select id, workflow, source from _vt.vreplication`) and fix the rule so each has a valid keyrange or SELECT filter.","Cancel and recreate the workflow using MoveTables/Materialize so rules are generated correctly.","If rows were hand-edited or written by external tooling, stop doing so — always create/modify streams via vtctldclient.","Check the Vitess version that created the rows for format changes between versions."],"exampleFix":"// before: {match: \"user\", filter: \"\"}\n// after: {match: \"user\", filter: \"select * from user where in_keyrange(-40)\"} — or recreate the workflow","handlingStrategy":"validation","validationCode":"-- Each rule must have a non-empty filter (keyrange or SELECT)\nSELECT id, workflow FROM _vt.vreplication\nWHERE JSON_EXTRACT(source, '$.filter.rules[*].filter') IS NULL\n   OR JSON_SEARCH(source, 'one', '') IS NOT NULL;","typeGuard":"func ruleHasFilter(r *binlogdatapb.Rule) bool { return r != nil && r.Filter != \"\" }","tryCatchPattern":null,"preventionTips":["Create and modify vreplication rules only via vtctldclient, never direct SQL.","Validate generated filter rules after any custom tooling touches workflows."],"tags":["vitess","vreplication","filter-rules","corrupt-state"],"backgroundTag":"empty-filter-rule","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}