{"record":{"id":"881ea7bae3aa6ed4","repo":"vitessio/vitess","slug":"no-tables-in-workflow-s-s","errorCode":null,"errorMessage":"no tables in workflow %s.%s","messagePattern":"no tables in workflow (.+?)\\.(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/wrangler/traffic_switcher.go","lineNumber":267,"sourceCode":"\t// spec, so we need to use the source of the reverse workflow, which is the\n\t// target of the workflow initiated by the user for checking routing rules.\n\t// Similarly we use a target shard of the reverse workflow as the original\n\t// source to check if writes have been switched.\n\tif strings.HasSuffix(workflowName, \"_reverse\") {\n\t\treverse = true\n\t\t// Flip the source and target keyspaces.\n\t\tsourceKeyspace = state.TargetKeyspace\n\t\ttargetKeyspace = state.SourceKeyspace\n\t\tworkflowName = workflow.ReverseWorkflowName(workflowName)\n\t} else {\n\t\tsourceKeyspace = state.SourceKeyspace\n\t}\n\tif ts.MigrationType() == binlogdatapb.MigrationType_TABLES {\n\t\tstate.WorkflowType = workflow.TypeMoveTables\n\n\t\t// We assume a consistent state, so only choose routing rule for one table.\n\t\tif len(ts.Tables()) == 0 {\n\t\t\treturn nil, nil, fmt.Errorf(\"no tables in workflow %s.%s\", targetKeyspace, workflowName)\n\t\t}\n\t\ttable := ts.Tables()[0]\n\n\t\tif ts.isPartialMigration { // shard level traffic switching is all or nothing\n\t\t\tshardRoutingRules, err := wr.ts.GetShardRoutingRules(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\trules := shardRoutingRules.Rules\n\t\t\tfor _, rule := range rules {\n\t\t\t\tswitch rule.ToKeyspace {\n\t\t\t\tcase sourceKeyspace:\n\t\t\t\t\tstate.ShardsNotYetSwitched = append(state.ShardsNotYetSwitched, rule.Shard)\n\t\t\t\tcase targetKeyspace:\n\t\t\t\t\tstate.ShardsAlreadySwitched = append(state.ShardsAlreadySwitched, rule.Shard)\n\t\t\t\tdefault:\n\t\t\t\t\t// Not a relevant rule.","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/wrangler/traffic_switcher.go#L249-L285","documentation":"getWorkflowState builds the runtime state of a vreplication workflow (MoveTables/Migrate) and, for TABLES migration type, requires at least one table in the workflow since routing rules are derived from it. If ts.Tables() is empty, the workflow has no tables registered and state computation cannot proceed. Called from SwitchReads, SwitchWrites, and workflow construction.","triggerScenarios":"Calling MoveTables SwitchReads/SwitchWrites/CreateRoutingRules (or NewVReplicationWorkflow) for a workflow whose source tables list is empty — e.g. workflow created with no tables, all tables removed, or wrong workflow/keyspace name resolving to an empty table set.","commonSituations":"Typo in workflow name when running SwitchReads/SwitchWrites; MoveTables workflow whose tables were all dropped before traffic switch; partially-cleaned-up migration leaving an empty workflow entry; querying a keyspace that has a workflow record but no table registrations.","solutions":["Verify the workflow name and keyspace: `vtctldclient VReplicationExec <tablet> 'show workflows'`","If tables were removed unintentionally, recreate the MoveTables workflow with the intended table list","If the workflow is leftover/complete, clean it up (MoveTables Complete / Delete workflow) instead of switching traffic","Check the `_vt.vreplication` / workflow topology records to confirm which tables the workflow covers"],"exampleFix":"// before: switching traffic on a possibly empty workflow\nstate, _, err := wr.getWorkflowState(ctx, targetKeyspace, workflowName)\n// after: guard before switching\nif len(tables(workflowName)) == 0 {\n\treturn fmt.Errorf(\"workflow %s.%s has no tables; check name or recreate\", targetKeyspace, workflowName)\n}","handlingStrategy":"validation","validationCode":"wf, err := findWorkflow(ctx, targetKeyspace, workflowName)\nif err != nil {\n\treturn err\n}\nif len(wf.Tables) == 0 {\n\treturn fmt.Errorf(\"workflow %s.%s has no tables; verify name or recreate\", targetKeyspace, workflowName)\n}","typeGuard":"func workflowHasTables(ts wrangler.TrafficSwitcher) bool {\n\treturn ts.MigrationType() != binlogdatapb.MigrationType_TABLES || len(ts.Tables()) > 0\n}","tryCatchPattern":"if _, _, err := wr.SwitchReads(ctx, targetKeyspace, workflowName, tables, direction); err != nil {\n\tif strings.Contains(err.Error(), \"no tables in workflow\") {\n\t\t// check `show workflows` and workflow name spelling\n\t}\n\treturn err\n}","preventionTips":["Verify workflow name and keyspace with `show workflows` before switching traffic","Clean up completed/empty workflows with MoveTables Complete","Never drop all tables from a workflow you still plan to switch"],"tags":["vreplication","movetables","workflow"],"backgroundTag":"empty-workflow-tables","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}