{"record":{"id":"99af8c3c1d4af1d3","repo":"vitessio/vitess","slug":"unexpected-rule-in-vreplication-v","errorCode":null,"errorMessage":"unexpected rule in vreplication: %v","messagePattern":"unexpected rule in vreplication: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/workflow/stream_migrator.go","lineNumber":1129,"sourceCode":"// 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\n\t}\n\n\tsel, ok := statement.(*sqlparser.Select)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected query: %v\", rule.Filter)","sourceCodeStart":1111,"sourceCodeEnd":1147,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/workflow/stream_migrator.go#L1111-L1147","documentation":"templatizeRule rejects rules whose Filter equals vreplication.ExcludeStr (\"exclude\"). The exclude marker means 'do not replicate this table', which is meaningless in the context of migrating an existing stream — the stream shouldn't contain such a rule at all — so this error flags an unexpected/invalid rule shape during migration templatization.","triggerScenarios":"templatize -> templatizeRule encountering rule.Filter == vreplication.ExcludeStr while migrating streams — i.e. a vreplication stream's filter contains an exclude rule (typically from a MoveTables workflow that excluded a table) and the user attempts to migrate that workflow to new shards.","commonSituations":"Migrating a MoveTables workflow that was created with table exclusions; hand-added exclude rules in _vt.vreplication; using a newer exclude feature on a workflow later migrated by code that doesn't support it.","solutions":["Remove the excluded table from the migration scope: recreate the workflow's filter without the exclude rule (exclude rules only make sense at MoveTables setup, not stream migration).","If the table must stay excluded, recreate the MoveTables workflow excluding that table up front rather than via exclude rules in a migratable stream, or migrate the streams without that rule.","Cancel and re-create the workflow via vtctldclient so the generated filter contains only selectable rules.","Upgrade Vitess if a newer version supports migrating streams containing exclude rules."],"exampleFix":"// before: rules include {match: \"orders\", filter: \"exclude\"}\n// after: recreate workflow excluding 'orders' at creation time so no exclude rule exists in the migrated stream","handlingStrategy":"validation","validationCode":"-- Detect exclude rules in streams about to be migrated\nSELECT id, workflow FROM _vt.vreplication\nWHERE JSON_SEARCH(JSON_EXTRACT(source, '$.filter.rules[*].filter'), 'one', 'exclude') IS NOT NULL;","typeGuard":"func hasExcludeRule(rules []*binlogdatapb.Rule) bool {\n    for _, r := range rules {\n        if r.Filter == vreplication.ExcludeStr { return true }\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Specify table exclusions at workflow creation time (MoveTables --exclude), not by editing rules afterwards.","Before stream migration, list filter rules and remove any exclude entries by recreating the workflow.","Check Vitess release notes for exclude-rule support in stream migration before combining the features."],"tags":["vitess","vreplication","filter-rules","excluded-table"],"backgroundTag":"unexpected-exclude-rule","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}