{"record":{"id":"dea136fd70173035","repo":"vitessio/vitess","slug":"tablet-v-type-change-v-v-is-not-an-allowed-t-dea136","errorCode":null,"errorMessage":"tablet %v type change %v -> %v is not an allowed transition for ChangeTabletType","messagePattern":"tablet (.+?) type change (.+?) -> (.+?) is not an allowed transition for ChangeTabletType","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/wrangler/tablet.go","lineNumber":102,"sourceCode":"\t}\n\n\treturn nil\n}\n\n// ChangeTabletType changes the type of tablet and recomputes all\n// necessary derived paths in the serving graph, if necessary.\n//\n// Note we don't update the primary record in the Shard here, as we\n// can't ChangeType from and out of primary anyway.\nfunc (wr *Wrangler) ChangeTabletType(ctx context.Context, tabletAlias *topodatapb.TabletAlias, tabletType topodatapb.TabletType) error {\n\t// Load tablet to find endpoint, and keyspace and shard assignment.\n\tti, err := wr.ts.GetTablet(ctx, tabletAlias)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !topo.IsTrivialTypeChange(ti.Type, tabletType) {\n\t\treturn fmt.Errorf(\"tablet %v type change %v -> %v is not an allowed transition for ChangeTabletType\", tabletAlias, ti.Type, tabletType)\n\t}\n\n\t// We should clone the tablet and change its type to the expected type before checking the durability rules\n\t// Since we want to check the durability rules for the desired state and not before we make that change\n\texpectedTablet := ti.CloneVT()\n\texpectedTablet.Type = tabletType\n\tsemiSync, err := wr.shouldSendSemiSyncAck(ctx, expectedTablet)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// and ask the tablet to make the change\n\treturn wr.tmc.ChangeType(ctx, ti.Tablet, tabletType, semiSync)\n}\n\n// StartReplication is used to start replication on the specified tablet\n// It also finds out if the tablet should be sending semi-sync ACKs or not.\nfunc (wr *Wrangler) StartReplication(ctx context.Context, tablet *topodatapb.Tablet) error {\n\tsemiSync, err := wr.shouldSendSemiSyncAck(ctx, tablet)","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/wrangler/tablet.go#L84-L120","documentation":"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.","triggerScenarios":"Running `vtctldclient ChangeTabletType <alias> <type>` where topo.IsTrivialTypeChange(current, desired) is false, e.g. REPLICA->PRIMARY, PRIMARY->REPLICA, SPARE->PRIMARY.","commonSituations":"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.","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"],"exampleFix":"// before: rejected transition\nwr.ChangeTabletType(ctx, alias, topodatapb.TabletType_PRIMARY)\n// after: promote via reparent\nwr.ts.ReparentShard(ctx, \"ks\", \"-\", topoproto.TabletAlias(alias)) // or PlannedReparentShard via vtctldclient","handlingStrategy":"validation","validationCode":"ti, err := wr.ts.GetTablet(ctx, alias)\nif err != nil {\n\treturn err\n}\nif !topo.IsTrivialTypeChange(ti.Type, desiredType) {\n\treturn fmt.Errorf(\"use PlannedReparentShard for %s -> %s\", ti.Type, desiredType)\n}","typeGuard":"func isTrivialTransition(from, to topodatapb.TabletType) bool {\n\treturn topo.IsTrivialTypeChange(from, to)\n}","tryCatchPattern":"if err := wr.ChangeTabletType(ctx, alias, desired); err != nil {\n\tif strings.Contains(err.Error(), \"not an allowed transition\") {\n\t\t// fall back to reparent workflow for non-trivial moves\n\t}\n\treturn err\n}","preventionTips":["Restrict ChangeTabletType to REPLICA<->RDONLY/SPARE moves","Use PlannedReparentShard for primary promotion/demotion","Check current tablet type before choosing the operation"],"tags":["tablet-management","reparenting","topology"],"backgroundTag":"invalid-tablet-type-transition","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}