vitessio/vitess · error

shard %s is still serving

Error message

shard %s is still serving

What it means

During workflow validation (check for whether a migration has fully completed, e.g. before finalizing a shard migration), this check walks each migration source shard and records an error if the shard's primary is still marked IsPrimaryServing. A shard that still serves traffic is not safe to consider migrated/decommissioned. The error is recorded per shard via an AllErrorRecorder inside ForAllSources.

Source

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

	hasher := fnv.New64()
	hasher.Write([]byte(targetKeyspace))

	for _, s := range expanded {
		hasher.Write([]byte(s))
	}

	// Convert to int64 after dropping the highest bit.
	return int64(hasher.Sum64() & math.MaxInt64)
}

func doValidateWorkflowHasCompleted(ctx context.Context, ts *trafficSwitcher) error {
	wg := sync.WaitGroup{}
	rec := concurrency.AllErrorRecorder{}
	if ts.MigrationType() == binlogdatapb.MigrationType_SHARDS {
		_ = ts.ForAllSources(func(source *MigrationSource) error {
			wg.Add(1)
			if source.GetShard().IsPrimaryServing {
				rec.RecordError(fmt.Errorf("shard %s is still serving", source.GetShard().ShardName()))
			}
			wg.Done()
			return nil
		})
	} else {
		_ = ts.ForAllTargets(func(target *MigrationTarget) error {
			wg.Add(1)
			defer wg.Done()
			res, err := ts.ws.tmc.ReadVReplicationWorkflow(ctx, target.GetPrimary().Tablet, &tabletmanagerdatapb.ReadVReplicationWorkflowRequest{
				Workflow: ts.WorkflowName(),
			})
			if err != nil {
				rec.RecordError(err)
				return nil
			}
			for _, stream := range res.Streams {
				if stream.Message != Frozen {
					rec.RecordError(fmt.Errorf("vreplication streams are not frozen on tablet %d", target.GetPrimary().Alias.Uid))

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Complete the traffic switch (SwitchTraffic) for the source shards so serving is disabled before finalizing.
  2. Check the shard record (`vtctldclient GetTablets` / topo) and confirm IsPrimaryServing=false on migrated source primaries.
  3. If serving was already drained but the flag is stale, refresh/repair the topo record via the proper vtctldclient commands rather than finalizing the workflow.
Defensive patterns

Strategy: validation

Validate before calling

// verify source primaries are no longer serving before completing the workflow
for _, s := range sourceShards {
    if shardPrimaryInfo(ks, s).IsPrimaryServing {
        return fmt.Errorf("shard %s still serving; run SwitchTraffic first", s)
    }
}

Prevention

When it happens

Trigger: Running validateWorkflowHasCompleted (traffic validation for MigrateTables/Reshard of type SHARDS) while the source shards' primaries still have IsPrimaryServing=true in the topo — i.e. PRS/traffic switch away from those shards has not happened.

Common situations: Attempting to complete a ReshardWorkflow before SwitchTraffic drained reads/writes; a failed or skipped traffic switch step; manual topo edits leaving the serving flag set.

Related errors


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