vitessio/vitess · error
routing still exists from keyspace %s table %s to %s
Error message
routing still exists from keyspace %s table %s to %s
What it means
As a final completion check, the workflow validator reads the current RoutingRules and verifies that no routing rule still points a `fromTable` at a source-keyspace table participating in the workflow. If a rule maps traffic into the source keyspace's table (e.g. customer.t still routed via a MoveTables rule), the migration is not fully cut over and this error is recorded.
Source
Thrown at go/vt/vtctl/workflow/utils.go:596
}
}
return nil
})
}
wg.Wait()
if !ts.keepRoutingRules {
// Check if table is routable.
if ts.MigrationType() == binlogdatapb.MigrationType_TABLES {
rules, err := topotools.GetRoutingRules(ctx, ts.TopoServer())
if err != nil {
rec.RecordError(errors.New("could not get RoutingRules"))
}
for fromTable, toTables := range rules {
for _, toTable := range toTables {
for _, table := range ts.Tables() {
if toTable == fmt.Sprintf("%s.%s", ts.SourceKeyspaceName(), table) {
rec.RecordError(fmt.Errorf("routing still exists from keyspace %s table %s to %s", ts.SourceKeyspaceName(), table, fromTable))
}
}
}
}
}
}
if rec.HasErrors() {
return fmt.Errorf("%s", strings.Join(rec.ErrorStrings(), "\n"))
}
return nil
}
// ReverseWorkflowName returns the "reversed" name of a workflow. For a
// "forward" workflow, this is the workflow name with "_reverse" appended, and
// for a "reversed" workflow, this is the workflow name with the "_reverse"
// suffix removed.
func ReverseWorkflowName(workflow string) string {
if strings.HasSuffix(workflow, reverseSuffix) {View on GitHub (pinned to 01a25a7d17)
Solutions
- Run the workflow's traffic-switch/finalize step that removes the routing rules (SwitchTraffic with all tables, or RemoveRoutingRule for the stale entries).
- Inspect `vtctldclient GetRoutingRules` and delete rules whose to-tables point at sourceKeyspace.<table>.
- Re-run validation after cleaning the rules; it should find no routing into the source keyspace.
Example fix
// before (routing rules still contain) // from: customer.t -> [ks1.t] // error: routing still exists from keyspace ks1 table t to customer.t // after vtctldclient RemoveRoutingRule --table=customer.t vtctldclient ApplyRoutingRules --rules-file=cleaned.json
Defensive patterns
Strategy: validation
Validate before calling
// ensure no routing rule targets the source keyspace tables
rules := getRoutingRules()
for from, tos := range rules {
for _, to := range tos {
if strings.HasPrefix(to, sourceKeyspace+".") {
return fmt.Errorf("stale routing rule %s -> %s", from, to)
}
}
} Prevention
- Run GetRoutingRules and clean stale entries before finalizing a workflow.
- Complete the full SwitchTraffic sequence so routing rules are removed automatically.
- Avoid running overlapping workflows that re-add routing to the source keyspace.
When it happens
Trigger: Running validateWorkflowHasCompleted (via SwitchTraffic/final validation) while RoutingRules still contain entries mapping a from-table to `sourceKeyspace.table` for a table in the workflow's table set — i.e. the RemoveRoutingRule step never ran or added rules back.
Common situations: Finalizing MoveTables before switching routing rules; a second workflow re-adding routing to the source keyspace; partial traffic switch leaving some table rules in place.
Related errors
- vreplication streams are not frozen on tablet %d
- either source or target shards are missing
- could not get RoutingRules
- validateWorkflowName.VReplicationExec: <dynamic validation.m
- range %d should be >= %d
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/aee739e94399628c.
Report an issue: GitHub.