vitessio/vitess · error

unexpected rule in vreplication: %v

Error message

unexpected rule in vreplication: %v

What it means

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.

Source

Thrown at go/vt/vtctl/workflow/stream_migrator.go:1129

// This can then be used by go's template package to substitute other keyrange values.
func (sm *StreamMigrator) templatizeRule(ctx context.Context, rule *binlogdatapb.Rule) (StreamType, error) {
	vtable, ok := sm.ts.SourceKeyspaceSchema().Tables[rule.Match]
	if !ok && !schema.IsInternalOperationTableName(rule.Match) {
		return StreamTypeUnknown, fmt.Errorf("table %v not found in vschema", rule.Match)
	}

	if vtable != nil && vtable.Type == vindexes.TypeReference {
		return StreamTypeReference, nil
	}

	switch {
	case rule.Filter == "":
		return StreamTypeUnknown, fmt.Errorf("rule %v does not have a select expression in vreplication", rule)
	case key.IsValidKeyRange(rule.Filter):
		rule.Filter = "{{.}}"
		return StreamTypeSharded, nil
	case rule.Filter == vreplication.ExcludeStr:
		return StreamTypeUnknown, fmt.Errorf("unexpected rule in vreplication: %v", rule)
	default:
		if err := sm.templatizeKeyRange(ctx, rule); err != nil {
			return StreamTypeUnknown, err
		}

		return StreamTypeSharded, nil
	}
}

func (sm *StreamMigrator) templatizeKeyRange(ctx context.Context, rule *binlogdatapb.Rule) error {
	statement, err := sm.parser.Parse(rule.Filter)
	if err != nil {
		return err
	}

	sel, ok := statement.(*sqlparser.Select)
	if !ok {
		return fmt.Errorf("unexpected query: %v", rule.Filter)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. 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).
  2. 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.
  3. Cancel and re-create the workflow via vtctldclient so the generated filter contains only selectable rules.
  4. Upgrade Vitess if a newer version supports migrating streams containing exclude rules.

Example fix

// before: rules include {match: "orders", filter: "exclude"}
// after: recreate workflow excluding 'orders' at creation time so no exclude rule exists in the migrated stream
Defensive patterns

Strategy: validation

Validate before calling

-- Detect exclude rules in streams about to be migrated
SELECT id, workflow FROM _vt.vreplication
WHERE JSON_SEARCH(JSON_EXTRACT(source, '$.filter.rules[*].filter'), 'one', 'exclude') IS NOT NULL;

Type guard

func hasExcludeRule(rules []*binlogdatapb.Rule) bool {
    for _, r := range rules {
        if r.Filter == vreplication.ExcludeStr { return true }
    }
    return false
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/99af8c3c1d4af1d3. Report an issue: GitHub.