{"record":{"id":"acc939daafe757d1","repo":"vitessio/vitess","slug":"tablet-s-type-has-changed-from-s-to-s-restarti","errorCode":null,"errorMessage":"tablet %s type has changed from %s to %s, restarting vstream","messagePattern":"tablet (.+?) type has changed from (.+?) to (.+?), restarting vstream","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"go/vt/vtgate/vstream_manager.go","lineNumber":735,"sourceCode":"\t\t\tCell:       vs.vsm.cell,\n\t\t}\n\t\ttabletConn, err := vs.vsm.resolver.GetGateway().QueryServiceByAlias(ctx, tablet.Alias, target)\n\t\tif err != nil {\n\t\t\tlog.Error(err.Error())\n\t\t\treturn vterrors.Wrapf(err, \"failed to get tablet connection to %s\", tabletAliasString)\n\t\t}\n\n\t\terrCh := make(chan error, 1)\n\t\tgo func() {\n\t\t\t_ = tabletConn.StreamHealth(ctx, func(shr *querypb.StreamHealthResponse) error {\n\t\t\t\tvar err error\n\t\t\t\tswitch {\n\t\t\t\tcase ctx.Err() != nil:\n\t\t\t\t\terr = vterrors.Wrapf(ctx.Err(), \"context ended while streaming tablet health from %s\", tabletAliasString)\n\t\t\t\tcase shr == nil || shr.RealtimeStats == nil || shr.Target == nil:\n\t\t\t\t\terr = fmt.Errorf(\"health check failed on %s\", tabletAliasString)\n\t\t\t\tcase vs.tabletType != shr.Target.TabletType:\n\t\t\t\t\terr = fmt.Errorf(\"tablet %s type has changed from %s to %s, restarting vstream\",\n\t\t\t\t\t\ttopoproto.TabletAliasString(tablet.Alias), vs.tabletType, shr.Target.TabletType)\n\t\t\t\tcase shr.RealtimeStats.HealthError != \"\":\n\t\t\t\t\terr = fmt.Errorf(\"tablet %s is no longer healthy: %s, restarting vstream\",\n\t\t\t\t\t\ttopoproto.TabletAliasString(tablet.Alias), shr.RealtimeStats.HealthError)\n\t\t\t\tcase shr.RealtimeStats.ReplicationLagSeconds > uint32(discovery.GetLowReplicationLag().Seconds()):\n\t\t\t\t\terr = fmt.Errorf(\"tablet %s has a replication lag of %d seconds which is beyond the value provided in --discovery_low_replication_lag of %s so the tablet is no longer considered healthy, restarting vstream\",\n\t\t\t\t\t\ttopoproto.TabletAliasString(tablet.Alias), shr.RealtimeStats.ReplicationLagSeconds, discovery.GetLowReplicationLag())\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warn(fmt.Sprintf(\"Tablet state changed: %s, attempting to restart\", err))\n\t\t\t\t\terr = vterrors.Wrapf(err, \"error streaming tablet health from %s\", tabletAliasString)\n\t\t\t\t\terrCh <- err\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}()\n","sourceCodeStart":717,"sourceCodeEnd":753,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/vstream_manager.go#L717-L753","documentation":"While streaming health, if shr.Target.TabletType differs from the tablet type the VStreamer initially selected, it errors 'tablet %s type has changed from %s to %s, restarting vstream'. This is intentional fail-fast behavior: the stream was opened against, say, a REPLICA, but the tablet changed type (e.g. promoted or repurposed), so the stream must restart to pick a valid source.","triggerScenarios":"A tablet reparent/promotion or TabletType change (replica<->rdonly, serving->primary) occurs mid-vstream; vtctldclient SetWritable/ChangeTabletType issued while MoveTables/Reshard is running.","commonSituations":"Running Reshard/MoveTables concurrent with a failover; automation resharding rdonly tablets; DR switchover during an ongoing migration.","solutions":["Let the vstream restart — it re-selects a tablet of the required type automatically.","Check tablet history (vtctldclient GetTablets) to see what changed the type.","If a failover occurred, verify replication caught up and the workflow resumed (copy_state / VReplication status).","Avoid changing tablet types during active VReplication migrations; pause workflows (VReplicationExec pause) first.","If a tablet flaps types repeatedly, fix the automation or reparent loop causing it."],"exampleFix":"// before: promote replica mid-migration\nvtctldclient PlannedReparentShard ... # while MoveTables runs → type-change error\n// after\nvtctldclient VReplicationExec pause; vtctldclient PlannedReparentShard ...; vtctldclient VReplicationExec resume","handlingStrategy":"retry","validationCode":"// before migrations, pin tablet types:\n// vtctldclient GetTablets → ensure no pending reparent/type change scheduled\n// check serving graph: vtctldclient GetSrvVSchema","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"type has changed\") {\n    // expected during failover: re-select source tablet and restart\n    return restartVStreamWithNewSource(ctx)\n}","preventionTips":["Don't run failovers concurrently with VReplication workflows","Pause workflows during planned type changes","Use PRS with workflows paused","Alert on tablet_type flapping"],"tags":["vreplication","vstream","tablet-type","failover"],"backgroundTag":"tablet-type-changed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}