{"record":{"id":"fd88562979712294","repo":"vitessio/vitess","slug":"unexpected-there-are-no-tables-to-copy","errorCode":null,"errorMessage":"unexpected: there are no tables to copy","messagePattern":"unexpected: there are no tables to copy","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vreplication/vcopier.go","lineNumber":319,"sourceCode":"\tvar tableToCopy string\n\tcopyState := make(map[string]*sqltypes.Result)\n\tfor _, row := range qr.Rows {\n\t\ttableName := row[0].ToString()\n\t\tlastpk := row[1].ToString()\n\t\tif tableToCopy == \"\" {\n\t\t\ttableToCopy = tableName\n\t\t}\n\t\tcopyState[tableName] = nil\n\t\tif lastpk != \"\" {\n\t\t\tvar r querypb.QueryResult\n\t\t\tif err := prototext.Unmarshal([]byte(lastpk), &r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcopyState[tableName] = sqltypes.Proto3ToResult(&r)\n\t\t}\n\t}\n\tif len(copyState) == 0 {\n\t\treturn errors.New(\"unexpected: there are no tables to copy\")\n\t}\n\tif err := vc.catchup(ctx, copyState); err != nil {\n\t\treturn err\n\t}\n\treturn vc.copyTable(ctx, tableToCopy, copyState)\n}\n\n// catchup replays events to the subset of the tables that have been copied\n// until replication is caught up. In order to stop, the seconds behind primary has\n// to fall below replicationLagTolerance.\nfunc (vc *vcopier) catchup(ctx context.Context, copyState map[string]*sqltypes.Result) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\tdefer vc.vr.stats.PhaseTimings.Record(\"catchup\", time.Now())\n\n\tsettings, err := binlogplayer.ReadVRSettings(vc.vr.dbClient, vc.vr.id)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vreplication/vcopier.go#L301-L337","documentation":"copyNext built a copyState map but it ended up empty, meaning no table data was actually copied before proceeding. The code treats this as an internal invariant violation (\"unexpected\"), since a valid copy phase should always have at least one table result in progress.","triggerScenarios":"copyNext finishes its table-copy loop without ever inserting into copyState — e.g. the table list to copy is empty or every table was skipped before a result was stored, then catchup/copyTable would run with nothing.","commonSituations":"Moving a keyspace/table set where no tables match the filter rules; a source tablet reporting no tables to copy; upstream state corruption where the table plan was empty.","solutions":["Verify the MoveTables/VReplication filter rules actually match existing tables on the source (check table names, keyspace)","Check the source tablet's table list / schema (SHOW TABLES) to confirm tables exist and are intended for copying","Inspect vreplication workflow status/logs to see which tables were planned; restart the workflow with corrected filters"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before starting the copy, confirm the filter matches at least one table on the source\ntables, _ := sourceConn.FetchAll(\"SHOW TABLES\", nil)\nmatched := filterRulesMatching(tables, workflowRules)\nif len(matched) == 0 { return fmt.Errorf(\"no tables match the workflow filter rules\") }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Verify filter rules match real table names (case/suffix aware) before MoveTables","Run a dry-run of the table plan","Check workflow status after start to confirm tables were planned"],"tags":["vreplication","vcopier","internal-error","table-copy"],"backgroundTag":"empty-copy-state","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}