vitessio/vitess · error
unexpected: there are no tables to copy
Error message
unexpected: there are no tables to copy
What it means
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.
Source
Thrown at go/vt/vttablet/tabletmanager/vreplication/vcopier.go:319
var tableToCopy string
copyState := make(map[string]*sqltypes.Result)
for _, row := range qr.Rows {
tableName := row[0].ToString()
lastpk := row[1].ToString()
if tableToCopy == "" {
tableToCopy = tableName
}
copyState[tableName] = nil
if lastpk != "" {
var r querypb.QueryResult
if err := prototext.Unmarshal([]byte(lastpk), &r); err != nil {
return err
}
copyState[tableName] = sqltypes.Proto3ToResult(&r)
}
}
if len(copyState) == 0 {
return errors.New("unexpected: there are no tables to copy")
}
if err := vc.catchup(ctx, copyState); err != nil {
return err
}
return vc.copyTable(ctx, tableToCopy, copyState)
}
// catchup replays events to the subset of the tables that have been copied
// until replication is caught up. In order to stop, the seconds behind primary has
// to fall below replicationLagTolerance.
func (vc *vcopier) catchup(ctx context.Context, copyState map[string]*sqltypes.Result) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
defer vc.vr.stats.PhaseTimings.Record("catchup", time.Now())
settings, err := binlogplayer.ReadVRSettings(vc.vr.dbClient, vc.vr.id)
if err != nil {
return errView on GitHub (pinned to 01a25a7d17)
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
Defensive patterns
Strategy: validation
Validate before calling
// Before starting the copy, confirm the filter matches at least one table on the source
tables, _ := sourceConn.FetchAll("SHOW TABLES", nil)
matched := filterRulesMatching(tables, workflowRules)
if len(matched) == 0 { return fmt.Errorf("no tables match the workflow filter rules") } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- work queue is not open
- CopyAll was interrupted due to context expiration
- plan not found for table: %s, current plans are: %#v
- expecting field event first, got: %v
- failed to marshal pk fields and value into query result: %s
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/fd88562979712294.
Report an issue: GitHub.