vitessio/vitess · error

cannot delete tablet %v as it is a primary, use allow_primar

Error message

cannot delete tablet %v as it is a primary, use allow_primary flag

What it means

DeleteTablet refuses to delete a tablet that is currently the shard primary unless the allowPrimary flag is explicitly set. This is a safety guard against accidentally removing a serving primary from the topology. The check queries the tablet type and only errors when wasPrimary is true and allowPrimary is false.

Source

Thrown at go/vt/wrangler/tablet.go:53

// Tablet related methods for wrangler

// DeleteTablet removes a tablet from a shard.
// - if allowPrimary is set, we can Delete a primary tablet (and clear
// its record from the Shard record if it was the primary).
func (wr *Wrangler) DeleteTablet(ctx context.Context, tabletAlias *topodatapb.TabletAlias, allowPrimary bool) (err error) {
	// load the tablet, see if we'll need to rebuild
	ti, err := wr.ts.GetTablet(ctx, tabletAlias)
	if err != nil {
		return err
	}

	wasPrimary, err := wr.isPrimaryTablet(ctx, ti)
	if err != nil && !topo.IsErrType(err, topo.NoNode) {
		return err
	}

	if wasPrimary && !allowPrimary {
		return fmt.Errorf("cannot delete tablet %v as it is a primary, use allow_primary flag", topoproto.TabletAliasString(tabletAlias))
	}

	// update the Shard object if the primary was scrapped.
	// we do this before calling DeleteTablet so that the operation can be retried in case of failure.
	if wasPrimary {
		// We lock the shard to not conflict with reparent operations.
		ctx, unlock, lockErr := wr.ts.LockShard(ctx, ti.Keyspace, ti.Shard, fmt.Sprintf("DeleteTablet(%v)", topoproto.TabletAliasString(tabletAlias)))
		if lockErr != nil {
			return lockErr
		}
		defer unlock(&err)

		// update the shard record's primary
		_, err := wr.ts.UpdateShardFields(ctx, ti.Keyspace, ti.Shard, func(si *topo.ShardInfo) error {
			if !topoproto.TabletAliasEqual(si.PrimaryAlias, tabletAlias) {
				wr.Logger().Warningf("Deleting primary %v from shard %v/%v but primary in Shard object was %v", topoproto.TabletAliasString(tabletAlias), ti.Keyspace, ti.Shard, topoproto.TabletAliasString(si.PrimaryAlias))
				return topo.NewError(topo.NoUpdateNeeded, si.Keyspace()+"/"+si.ShardName())
			}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Confirm the tablet really should be removed; if yes, pass allow_primary (e.g. `vtctldclient DeleteTablet --allow-primary <alias>`)
  2. Better: first reparent or convert the tablet to REPLICA (`vtctldclient PlannedReparentShard` or ChangeTabletType) then delete
  3. Check `vtctldclient GetTablet <alias>` to confirm the tablet's current type before deleting
  4. If the topology record is stale and the tablet is not actually a primary, remove the stale topo entry manually

Example fix

// before: fails on a primary
wr.DeleteTablet(ctx, alias, false)
// after: only delete non-primaries, or opt in explicitly
if isPrimary, _ := wr.isPrimaryTablet(ctx, ti); isPrimary {
	return fmt.Errorf("refusing to delete primary %s without explicit consent", alias)
}
wr.DeleteTablet(ctx, alias, true)
Defensive patterns

Strategy: validation

Validate before calling

ti, err := wr.ts.GetTablet(ctx, alias)
if err != nil {
	return err
}
if ti.Type == topodatapb.TabletType_PRIMARY && !allowPrimary {
	return fmt.Errorf("%s is PRIMARY; pass allow_primary or reparent first", alias)
}

Type guard

func isPrimaryTablet(ti *topodatapb.Tablet) bool {
	return ti != nil && ti.Type == topodatapb.TabletType_PRIMARY
}

Try / catch

if err := wr.DeleteTablet(ctx, alias, false); err != nil {
	if strings.Contains(err.Error(), "use allow_primary flag") {
		// confirm intent, then DeleteTablet(ctx, alias, true) or reparent first
	}
	return err
}

Prevention

When it happens

Trigger: Running `vtctldclient DeleteTablet <alias>` (commandDeleteTablet) on a tablet whose type is PRIMARY without passing allow_primary.

Common situations: Decommissioning tablets after a reparent where the old primary hasn't been converted to replica; scripted cleanup that blindly deletes all tablet aliases including the current primary; mistaken alias ordering when purging a shard.

Related errors


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