vitessio/vitess · error

shard %v/%v doesn't have a primary set

Error message

shard %v/%v doesn't have a primary set

What it means

LegacyBuildTargets requires each target shard in the workflow to have an elected primary so it can run VReplicationExec queries against it. When the shard record in the topology has a nil PrimaryAlias, the function aborts with this error, noting it usually stems from bad inputs — e.g. naming a shard that was never initialized or whose primary was removed.

Source

Thrown at go/vt/vtctl/workflow/utils.go:749

	getVReplicationWorkflowSubType := func(row sqltypes.RowNamedValues) binlogdatapb.VReplicationWorkflowSubType {
		i, _ := row["workflow_sub_type"].ToInt32()
		return binlogdatapb.VReplicationWorkflowSubType(i)
	}

	// We check all shards in the target keyspace. Not all of them may have a
	// stream. For example, if we're splitting -80 to [-40,40-80], only those
	// two target shards will have vreplication streams, and the other shards in
	// the target keyspace will not.
	for _, targetShard := range targetShards {
		si, err := ts.GetShard(ctx, targetKeyspace, targetShard)
		if err != nil {
			return nil, err
		}

		if si.PrimaryAlias == nil {
			// This can happen if bad inputs are given.
			return nil, fmt.Errorf("shard %v/%v doesn't have a primary set", targetKeyspace, targetShard)
		}

		primary, err := ts.GetTablet(ctx, si.PrimaryAlias)
		if err != nil {
			return nil, err
		}

		// NB: changing the whitespace of this query breaks tests for now.
		// (TODO:@ajm188) extend FakeDBClient to be less whitespace-sensitive on
		// expected queries.
		query := fmt.Sprintf("select id, source, message, cell, tablet_types, workflow_type, workflow_sub_type, defer_secondary_keys from _vt.vreplication where workflow=%s and db_name=%s", encodeString(workflow), encodeString(primary.DbName()))
		p3qr, err := tmc.VReplicationExec(ctx, primary.Tablet, query)
		if err != nil {
			return nil, err
		}

		if len(p3qr.Rows) < 1 {
			continue

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify the shard's state with vtctldclient GetShard <keyspace>/<shard> and confirm PrimaryAlias is set.
  2. Elect a primary via vtctldclient PlannedReparentShard or EmergencyReparentShard for that shard.
  3. Correct the shard list passed to the workflow command if the shard name was wrong or shouldn't be included.
  4. If the shard is truly empty/unused, remove it (vtctldclient DeleteShard) or drop it from the migration inputs.

Example fix

// before (shard -80 has no primary)
vtctldclient Reshard --workflow x --target-keyspace=ks SwitchTraffic --shards=-80
// after (elect primary first)
vtctldclient PlannedReparentShard ks/-80 --new-primary=zone1-101
Defensive patterns

Strategy: validation

Validate before calling

for _, shard := range targetShards {
	si, err := ts.GetShard(ctx, targetKeyspace, shard)
	if err != nil {
		return err
	}
	if si.PrimaryAlias == nil {
		return fmt.Errorf("precheck: %s/%s has no primary", targetKeyspace, shard)
	}
}

Type guard

func shardHasPrimary(si *topo.ShardInfo) bool { return si != nil && si.PrimaryAlias != nil }

Try / catch

ti, err := workflow.LegacyBuildTargets(ctx, ts, tmc, ks, wf, shards)
if err != nil {
	if strings.Contains(err.Error(), "doesn't have a primary set") {
		// reparent or fix shard list before retrying
	}
	return err
}

Prevention

When it happens

Trigger: Calling buildTrafficSwitcher → LegacyBuildTargets with a targetShards entry whose shard in topo has no primary: freshly created empty shard, primary tablet deleted/pruned without ERS, or a typo'd shard name pointing at an uninitialized shard.

Common situations: Running MoveTables/Reshard SwitchTraffic right after creating a new empty shard before reparenting; primary was deliberately removed during decommissioning; cluster recovered from topo backup where the shard record lost its primary alias.

Related errors


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