vitessio/vitess · error
tablet %v type change %v -> %v is not an allowed transition
Error message
tablet %v type change %v -> %v is not an allowed transition for ChangeTabletType
What it means
ChangeTabletType only permits 'trivial' type transitions (ones that don't affect replication topology, e.g. replica->rdonly). Requested transitions that would change serving duties — like replica->primary or primary->replica — are rejected with this error because those require reparent operations, not a simple type flip. The error echoes the current and requested types.
Source
Thrown at go/vt/wrangler/tablet.go:102
}
return nil
}
// ChangeTabletType changes the type of tablet and recomputes all
// necessary derived paths in the serving graph, if necessary.
//
// Note we don't update the primary record in the Shard here, as we
// can't ChangeType from and out of primary anyway.
func (wr *Wrangler) ChangeTabletType(ctx context.Context, tabletAlias *topodatapb.TabletAlias, tabletType topodatapb.TabletType) error {
// Load tablet to find endpoint, and keyspace and shard assignment.
ti, err := wr.ts.GetTablet(ctx, tabletAlias)
if err != nil {
return err
}
if !topo.IsTrivialTypeChange(ti.Type, tabletType) {
return fmt.Errorf("tablet %v type change %v -> %v is not an allowed transition for ChangeTabletType", tabletAlias, ti.Type, tabletType)
}
// We should clone the tablet and change its type to the expected type before checking the durability rules
// Since we want to check the durability rules for the desired state and not before we make that change
expectedTablet := ti.CloneVT()
expectedTablet.Type = tabletType
semiSync, err := wr.shouldSendSemiSyncAck(ctx, expectedTablet)
if err != nil {
return err
}
// and ask the tablet to make the change
return wr.tmc.ChangeType(ctx, ti.Tablet, tabletType, semiSync)
}
// StartReplication is used to start replication on the specified tablet
// It also finds out if the tablet should be sending semi-sync ACKs or not.
func (wr *Wrangler) StartReplication(ctx context.Context, tablet *topodatapb.Tablet) error {
semiSync, err := wr.shouldSendSemiSyncAck(ctx, tablet)View on GitHub (pinned to 01a25a7d17)
Solutions
- Use `vtctldclient PlannedReparentShard` to promote a replica or demote a primary safely
- For demotion during decommission, run ERS/PRS first so the tablet becomes REPLICA, then ChangeTabletType
- Only use ChangeTabletType for trivial moves (e.g. REPLICA<->RDONLY/SPARE)
- Check the tablet's current type with GetTablet before choosing the operation
Example fix
// before: rejected transition wr.ChangeTabletType(ctx, alias, topodatapb.TabletType_PRIMARY) // after: promote via reparent wr.ts.ReparentShard(ctx, "ks", "-", topoproto.TabletAlias(alias)) // or PlannedReparentShard via vtctldclient
Defensive patterns
Strategy: validation
Validate before calling
ti, err := wr.ts.GetTablet(ctx, alias)
if err != nil {
return err
}
if !topo.IsTrivialTypeChange(ti.Type, desiredType) {
return fmt.Errorf("use PlannedReparentShard for %s -> %s", ti.Type, desiredType)
} Type guard
func isTrivialTransition(from, to topodatapb.TabletType) bool {
return topo.IsTrivialTypeChange(from, to)
} Try / catch
if err := wr.ChangeTabletType(ctx, alias, desired); err != nil {
if strings.Contains(err.Error(), "not an allowed transition") {
// fall back to reparent workflow for non-trivial moves
}
return err
} Prevention
- Restrict ChangeTabletType to REPLICA<->RDONLY/SPARE moves
- Use PlannedReparentShard for primary promotion/demotion
- Check current tablet type before choosing the operation
When it happens
Trigger: Running `vtctldclient ChangeTabletType <alias> <type>` where topo.IsTrivialTypeChange(current, desired) is false, e.g. REPLICA->PRIMARY, PRIMARY->REPLICA, SPARE->PRIMARY.
Common situations: Operators trying to promote a replica to primary directly with ChangeTabletType instead of PlannedReparentShard; scripts demoting a primary by type change after a failed reparent; converting a primary to rdonly for teardown without first demoting it.
Related errors
- cannot delete tablet %v as it is a primary, use allow_primar
- not allowed: deny-all security-policy enforced
- not allowed: read-only security-policy enforced
- invalid choice for enum
- value must be either a float64 (interpreted as seconds) or a
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/dea136fd70173035.
Report an issue: GitHub.