vitessio/vitess · error

shard %v/%v has no source shard

Error message

shard %v/%v has no source shard

What it means

WaitForFilteredReplication waits until replication lag on a shard's primary (from its SourceShards) drops below a maxDelay. It requires the shard to have at least one SourceShard; a shard with none is not receiving filtered replication, so there is nothing to wait for and the call fails immediately.

Source

Thrown at go/vt/wrangler/split.go:86

		// so let's be safe and abort right here.
		if len(si.SourceShards) > 0 {
			return fmt.Errorf("shard %v/%v already has SourceShards, not overwriting them (full record: %v)", keyspace, shard, si.Shard)
		}

		si.SourceShards = sourceShards
		return nil
	})
	return err
}

// WaitForFilteredReplication will wait until the Filtered Replication process has finished.
func (wr *Wrangler) WaitForFilteredReplication(ctx context.Context, keyspace, shard string, maxDelay time.Duration) error {
	shardInfo, err := wr.TopoServer().GetShard(ctx, keyspace, shard)
	if err != nil {
		return err
	}
	if len(shardInfo.SourceShards) == 0 {
		return fmt.Errorf("shard %v/%v has no source shard", keyspace, shard)
	}
	if !shardInfo.HasPrimary() {
		return fmt.Errorf("shard %v/%v has no primary", keyspace, shard)
	}
	alias := shardInfo.PrimaryAlias
	tabletInfo, err := wr.TopoServer().GetTablet(ctx, alias)
	if err != nil {
		return err
	}

	// Always run an explicit healthcheck first to make sure we don't see any outdated values.
	// This is especially true for tests and automation where there is no pause of multiple seconds
	// between commands and the periodic healthcheck did not run again yet.
	if err := wr.TabletManagerClient().RunHealthCheck(ctx, tabletInfo.Tablet); err != nil {
		return fmt.Errorf("failed to run explicit healthcheck on tablet: %v err: %v", tabletInfo, err)
	}

	conn, err := tabletconn.GetDialer()(ctx, tabletInfo.Tablet, grpcclient.FailFast(false))

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify with `vtctldclient GetShard <keyspace>/<shard>` that source_shards is non-empty; if empty, complete the MoveTables/Reshard step that adds it first.
  2. Confirm you are targeting the destination shard, not the source shard.
  3. If migration finished and sources were removed, the wait is unnecessary — skip it.

Example fix

// before
vtctldclient WaitForFilteredReplication customer/0 30s
// error: shard customer/0 has no source shard
// after
vtctldclient MoveTables --workflow ledger --source commerce customer   # sets up source shard
vtctldclient WaitForFilteredReplication customer/0 30s
Defensive patterns

Strategy: validation

Validate before calling

// Before WaitForFilteredReplication, ensure the shard has sources
shardInfo, _ := vtctldclientGetShard(keyspace, shard)
if len(shardInfo.SourceShards) == 0 {
    // run MoveTables/Reshard step that configures filtered replication first
    fmt.Printf("%s/%s has no SourceShards; configure filtered replication first\n", keyspace, shard)
}

Prevention

When it happens

Trigger: Calling WaitForFilteredReplication (via `vtctldclient WaitForFilteredReplication <keyspace/shard> <maxDelay>`) on a shard whose record has an empty SourceShards list.

Common situations: Running the wait command before MoveTables/Reshard actually configured the source shard; specifying the source keyspace/shard instead of the destination; automation calling wait after the migration completed and sources were removed.

Related errors


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