vitessio/vitess · error
invalid type transition %v: %v -> %v
Error message
invalid type transition %v: %v -> %v
What it means
During a dry-run ChangeTabletType, Vitess checks topo.IsTrivialTypeChange between the tablet's current type and the requested type. If the transition is not considered trivially safe to simulate/apply, this error names the alias and both types.
Source
Thrown at go/vt/vtctl/vtctl.go:1160
tabletAlias, err := topoproto.ParseTabletAlias(subFlags.Arg(0))
if err != nil {
return err
}
newType, err := parseTabletType(subFlags.Arg(1), topoproto.AllTabletTypes)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(ctx, topo.RemoteOperationTimeout)
defer cancel()
if *dryRun {
ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias)
if err != nil {
return fmt.Errorf("failed reading tablet %v: %v", tabletAlias, err)
}
if !topo.IsTrivialTypeChange(ti.Type, newType) {
return fmt.Errorf("invalid type transition %v: %v -> %v", tabletAlias, ti.Type, newType)
}
wr.Logger().Printf("- %v\n", fmtTabletAwkable(ti))
ti.Type = newType
wr.Logger().Printf("+ %v\n", fmtTabletAwkable(ti))
return nil
}
return wr.ChangeTabletType(ctx, tabletAlias, newType)
}
func commandPing(ctx context.Context, wr *wrangler.Wrangler, subFlags *pflag.FlagSet, args []string) error {
if err := subFlags.Parse(args); err != nil {
return err
}
if subFlags.NArg() != 1 {
return errors.New("the <tablet alias> argument is required for the Ping command")
}
tabletAlias, err := topoproto.ParseTabletAlias(subFlags.Arg(0))
if err != nil {View on GitHub (pinned to 01a25a7d17)
Solutions
- Check the tablet's current type (`vtctl GetTablet <alias>`) and pick a trivially-allowed target
- Use PlannedReparentShard/ EmergencyReparentShard for master transitions
- Wait for BACKUP/RESTORE tablets to finish before changing type
- Update automation to account for the IsTrivialTypeChange rules
Example fix
// before vtctl ChangeTabletType -dry-run zone1-0000000100 RDONLY # tablet is MASTER // after vtctl PlannedReparentShard commerce/0 zone1-0000000101 vtctl ChangeTabletType -dry-run zone1-0000000100 RDONLY
Defensive patterns
Strategy: validation
Validate before calling
CUR=$(vtctl GetTablet -format json "$ALIAS" | jq -r '.type')
# refuse non-trivial transitions up front
[[ "$CUR" == "MASTER" ]] && { echo "use reparent workflow, not ChangeTabletType"; exit 1; }
[[ "$CUR" == "BACKUP" || "$CUR" == "RESTORE" ]] && { echo "tablet busy: $CUR"; exit 1; } Try / catch
if err := runVtctl("ChangeTabletType", "--dry-run", alias, tt); err != nil {
if strings.Contains(err.Error(), "invalid type transition") {
// fetch current type, choose a reparent/backup-aware path
}
} Prevention
- Always read the tablet's current type before changing it
- Route master transitions through PlannedReparentShard/EmergencyReparentShard
- Avoid type changes while BACKUP/RESTORE is in progress
- Simulate with --dry-run first (which is where this check fires)
When it happens
Trigger: Running `vtctl ChangeTabletType --dry-run <alias> <newType>` where the current→new transition is not a trivial type change — e.g. attempting to change a MASTER tablet, or a transition the command considers invalid.
Common situations: Scripts that attempt master changes via ChangeTabletType instead of reparent workflows; changing a BACKUP/RESTORE tablet mid-operation; automations assuming all transitions are allowed.
Related errors
- the <tablet alias> and <db type> arguments are required for
- invalid tablet type %v: %v
- type %v is not one of: %v
- failed reading tablet %v: %v
- the <tablet alias> argument is required for the SetReadWrite
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/f298bd76e3122867.
Report an issue: GitHub.