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 err

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify the MoveTables/VReplication filter rules actually match existing tables on the source (check table names, keyspace)
  2. Check the source tablet's table list / schema (SHOW TABLES) to confirm tables exist and are intended for copying
  3. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/fd88562979712294. Report an issue: GitHub.