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
- Confirm the tablet really should be removed; if yes, pass allow_primary (e.g. `vtctldclient DeleteTablet --allow-primary <alias>`)
- Better: first reparent or convert the tablet to REPLICA (`vtctldclient PlannedReparentShard` or ChangeTabletType) then delete
- Check `vtctldclient GetTablet <alias>` to confirm the tablet's current type before deleting
- 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
- Always GetTablet to check type before deletion
- Demote primaries via PlannedReparentShard before decommissioning
- Gate allow_primary behind explicit operator consent in scripts
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
- shard %v/%v is still serving, cannot delete it, use even_if_
- tablet %v type change %v -> %v is not an allowed transition
- not allowed: deny-all security-policy enforced
- not allowed: read-only security-policy enforced
- invalid choice for enum
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/818dbd3f68cd46a3.
Report an issue: GitHub.