{"record":{"id":"7300061567c1f0e8","repo":"vitessio/vitess","slug":"could-not-get-routingrules","errorCode":null,"errorMessage":"could not get RoutingRules","messagePattern":"could not get RoutingRules","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/workflow/utils.go","lineNumber":590,"sourceCode":"\t\t\t\treturn nil\n\t\t\t}\n\t\t\tfor _, stream := range res.Streams {\n\t\t\t\tif stream.Message != Frozen {\n\t\t\t\t\trec.RecordError(fmt.Errorf(\"vreplication streams are not frozen on tablet %d\", target.GetPrimary().Alias.Uid))\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}\n\twg.Wait()\n\n\tif !ts.keepRoutingRules {\n\t\t// Check if table is routable.\n\t\tif ts.MigrationType() == binlogdatapb.MigrationType_TABLES {\n\t\t\trules, err := topotools.GetRoutingRules(ctx, ts.TopoServer())\n\t\t\tif err != nil {\n\t\t\t\trec.RecordError(errors.New(\"could not get RoutingRules\"))\n\t\t\t}\n\t\t\tfor fromTable, toTables := range rules {\n\t\t\t\tfor _, toTable := range toTables {\n\t\t\t\t\tfor _, table := range ts.Tables() {\n\t\t\t\t\t\tif toTable == fmt.Sprintf(\"%s.%s\", ts.SourceKeyspaceName(), table) {\n\t\t\t\t\t\t\trec.RecordError(fmt.Errorf(\"routing still exists from keyspace %s table %s to %s\", ts.SourceKeyspaceName(), table, fromTable))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif rec.HasErrors() {\n\t\treturn fmt.Errorf(\"%s\", strings.Join(rec.ErrorStrings(), \"\\n\"))\n\t}\n\treturn nil\n}\n","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/workflow/utils.go#L572-L608","documentation":"During workflow-completion validation, when --keep-routing-rules is not set, vtctl reads the global RoutingRules from the topology to verify no routing entries still point at the source keyspace. If reading RoutingRules fails, this error is recorded. Note: rules is then still used in the loop below, which is why a nil/failed read must be treated as fatal.","triggerScenarios":"Calling validateWorkflowHasCompleted (CompletionValidation for MoveTables) when topotools.GetRoutingRules fails — usually a topology read error (topo server unreachable, etcd/zookeeper down, permission problem) — while keepRoutingRules is false and MigrationType is TABLES.","commonSituations":"Topology backend outage or degraded quorum during cutover, wrong topo flags on vtctld, stale topo data preventing the RoutingRules global key from being read.","solutions":["Restore topology health and re-run completion validation (vtctldclient Workflow --workflow X MoveTablesComplete)","Check the topo server connection parameters and permissions of vtctld","If you intentionally want to keep routing rules, rerun with --keep-routing-rules so the RoutingRules read is skipped"],"exampleFix":"// before: read failure recorded but rules used anyway\nrules, err := topotools.GetRoutingRules(ctx, ts.TopoServer())\nif err != nil {\n    rec.RecordError(errors.New(\"could not get RoutingRules\"))\n}\n// after: stop before using possibly-nil rules\nrules, err := topotools.GetRoutingRules(ctx, ts.TopoServer())\nif err != nil {\n    rec.RecordError(errors.New(\"could not get RoutingRules\"))\n    return\n}","handlingStrategy":"validation","validationCode":"rules, err := topotools.GetRoutingRules(ctx, ts.TopoServer())\nif err != nil {\n    return fmt.Errorf(\"topology unreachable, cannot validate routing rules: %w\", err)\n}","typeGuard":"if rules == nil {\n    return errors.New(\"routing rules not loaded\")\n}","tryCatchPattern":"rec := &topo.TopoRecorder{}\nvalidateWorkflowHasCompleted(ctx, ts, wf)\nfor _, e := range rec.ErrorMessages() {\n    if strings.Contains(e, \"could not get RoutingRules\") {\n        return fmt.Errorf(\"fix topo server and retry completion validation: %s\", e)\n    }\n}","preventionTips":["Verify topo server health before running MoveTablesComplete","Use --keep-routing-rules only deliberately, never as a workaround for topo outages","Read routing rules in a retry loop with short backoff during validation"],"tags":["vreplication","routing-rules","topology"],"backgroundTag":"routing-rules-read-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}