vitessio/vitess · error

shard %s/%s has no primary

Error message

shard %s/%s has no primary

What it means

Returned by mysqlctl clone logic when the specified shard in the given keyspace has no primary tablet assigned, so there is no source to clone from.

Source

Thrown at go/vt/mysqlctl/clone.go:89

}

// CloneFromDonor clones data from the specified donor tablet using MySQL CLONE REMOTE and returns the GTID position of the cloned data. If mycnf is non-nil, CloneFromDonor may use it to restart mysqld locally when CLONE completes but MySQL cannot restart itself.
func CloneFromDonor(ctx context.Context, topoServer *topo.Server, mysqld MysqlDaemon, mycnf *Mycnf, keyspace, shard string) (replication.Position, error) {
	var donorAlias *topodatapb.TabletAlias
	var err error

	switch {
	case cloneFromPrimary && cloneFromTablet != "":
		return replication.Position{}, errors.New("--clone-from-primary and --clone-from-tablet are mutually exclusive")
	case cloneFromPrimary:
		// Look up the primary tablet from topology.
		log.Info(fmt.Sprintf("Looking up primary tablet for shard %s/%s for use as CLONE REMOTE donor", keyspace, shard))
		si, err := topoServer.GetShard(ctx, keyspace, shard)
		if err != nil {
			return replication.Position{}, fmt.Errorf("failed to get shard %s/%s: %v", keyspace, shard, err)
		}
		if topoproto.TabletAliasIsZero(si.PrimaryAlias) {
			return replication.Position{}, fmt.Errorf("shard %s/%s has no primary", keyspace, shard)
		}
		donorAlias = si.PrimaryAlias
		log.Info(fmt.Sprintf("Found primary tablet %s for use as CLONE REMOTE donor", topoproto.TabletAliasString(donorAlias)))
	case cloneFromTablet != "":
		// Parse the explicit donor tablet alias.
		log.Info(fmt.Sprintf("Using tablet %s for use as CLONE REMOTE donor", cloneFromTablet))
		donorAlias, err = topoproto.ParseTabletAlias(cloneFromTablet)
		if err != nil {
			return replication.Position{}, fmt.Errorf("invalid tablet alias %q: %v", cloneFromTablet, err)
		}
	default:
		return replication.Position{}, errors.New("no donor specified")
	}

	// Get donor tablet info from topology.
	donorTablet, err := topoServer.GetTablet(ctx, donorAlias)
	if err != nil {
		return replication.Position{}, fmt.Errorf("failed to get tablet %s from topology: %v", topoproto.TabletAliasString(donorAlias), err)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Check the shard with `vtctldclient GetShard <keyspace>/<shard>` — wait for or trigger primary election (PlannedReparentShard / EmergencyReparentShard).
  2. Choose a specific donor with --clone-from-tablet instead of --clone-from-primary.
  3. Ensure a tablet is started and promoted to primary for that shard.
  4. Verify you are targeting the correct keyspace/shard.

Example fix

// before
vttablet --clone-from-primary ...
// after
vttablet --clone-from-tablet zone1-0000000100 ...
Defensive patterns

Strategy: validation

Validate before calling

shardInfo, _ := topoServer.GetShard(ctx, keyspace, shard)
if shardInfo == nil || shardInfo.PrimaryAlias == nil || shardInfo.PrimaryAlias.Uid == 0 {
	return errors.New("shard has no primary; use --clone-from-tablet instead")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "has no primary") {
	// fall back to --clone-from-tablet with a known replica
}

Prevention

When it happens

Trigger: CloneFromDonor with --clone-from-primary on a shard with no primary (e.g., during resharding setup, after primary failure before failover, or a fresh shard with no tablets).

Common situations: Mid-failout/failover window, orphan shard, Principaled shard not yet elected, user targeting wrong shard that is intentionally empty.

Related errors


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