vitessio/vitess · error

shard %v/%v is still serving, cannot delete it, use even_if_

Error message

shard %v/%v is still serving, cannot delete it, use even_if_serving flag if needed

What it means

DeleteShard refuses to delete a shard whose Serving map still lists it in at least one cell, unless the caller passes evenIfServing. This is a safety guard: deleting a shard that vtgates are still routing traffic to would cause immediate query failures.

Source

Thrown at go/vt/wrangler/shard.go:75

	// Read the Shard object. If it's not there, try to clean up
	// the topology anyway.
	shardInfo, err := wr.ts.GetShard(ctx, keyspace, shard)
	if err != nil {
		if topo.IsErrType(err, topo.NoNode) {
			wr.Logger().Infof("Shard %v/%v doesn't seem to exist, cleaning up any potential leftover", keyspace, shard)
			return wr.ts.DeleteShard(ctx, keyspace, shard)
		}
		return err
	}

	servingCells, err := wr.ts.GetShardServingCells(ctx, shardInfo)
	if err != nil {
		return err
	}
	// Check the Serving map for the shard, we don't want to
	// remove a serving shard if not absolutely sure.
	if !evenIfServing && len(servingCells) > 0 {
		return fmt.Errorf("shard %v/%v is still serving, cannot delete it, use even_if_serving flag if needed", keyspace, shard)
	}

	cells, err := wr.ts.GetCellInfoNames(ctx)
	if err != nil {
		return err
	}

	// Go through all the cells.
	for _, cell := range cells {
		var aliases []*topodatapb.TabletAlias

		// Get the ShardReplication object for that cell. Try
		// to find all tablets that may belong to our shard.
		sri, err := wr.ts.GetShardReplication(ctx, cell, keyspace, shard)
		switch {
		case topo.IsErrType(err, topo.NoNode):
			// No ShardReplication object. It means the
			// topo is inconsistent. Let's read all the

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Confirm no vtgate traffic uses the shard, then rerun with the even_if_serving flag.
  2. If traffic already moved, rebuild/refresh the serving graph so the shard is no longer marked serving.
  3. Double-check keyspace/shard names - a typo may target a live shard.

Example fix

// before
vtctldclient DeleteShard customer/0
// after (verified no traffic)
vtctldclient DeleteShard --even_if_serving customer/0
Defensive patterns

Strategy: validation

Validate before calling

shardInfo, err := ts.GetShard(ctx, keyspace, shard)
if err == nil {
    for cell, serving := range shardInfo.ServingCells() /* or check serving map */ {
        if serving && !evenIfServing {
            return fmt.Errorf("shard %s/%s still serving in %s", keyspace, shard, cell)
        }
    }
}

Type guard

func isServing(servingCells []string) bool { return len(servingCells) > 0 }

Try / catch

err := wr.DeleteShard(ctx, keyspace, shard, evenIfServing, recursive)
if err != nil && strings.Contains(err.Error(), "is still serving") {
    // confirm traffic moved, rerun with evenIfServing=true
}

Prevention

When it happens

Trigger: vtctldclient DeleteShard is run on a shard still marked serving in one or more cells without the --even_if_serving flag.

Common situations: Cleaning up after a reshard where the new shards weren't fully switched over; accidentally targeting a still-live shard; stale serving entries after traffic moved but the topo wasn't refreshed.

Related errors


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