{"record":{"id":"be6f36fd28198b04","repo":"vitessio/vitess","slug":"cannot-lookup-primary-tablet-v-for-shard-v-v","errorCode":null,"errorMessage":"cannot lookup primary tablet %v for shard %v/%v: %w","messagePattern":"cannot lookup primary tablet (.+?) for shard (.+?)/(.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/topotools/tablet.go","lineNumber":204,"sourceCode":"//\n// It returns an error if:\n// - The shard does not exist in the topo.\n// - The shard has no primary in the topo.\n// - The shard primary does not think it is PRIMARY.\n// - The shard primary tablet record does not match the keyspace and shard of the replica.\nfunc GetShardPrimaryForTablet(ctx context.Context, ts *topo.Server, tablet *topodatapb.Tablet) (*topo.TabletInfo, error) {\n\tshard, err := ts.GetShard(ctx, tablet.Keyspace, tablet.Shard)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !shard.HasPrimary() {\n\t\treturn nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, \"no primary tablet for shard %v/%v\", tablet.Keyspace, tablet.Shard)\n\t}\n\n\tshardPrimary, err := ts.GetTablet(ctx, shard.PrimaryAlias)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot lookup primary tablet %v for shard %v/%v: %w\", topoproto.TabletAliasString(shard.PrimaryAlias), tablet.Keyspace, tablet.Shard, err)\n\t}\n\n\tif shardPrimary.Type != topodatapb.TabletType_PRIMARY {\n\t\treturn nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, \"TopologyServer has inconsistent state for shard primary %v\", topoproto.TabletAliasString(shard.PrimaryAlias))\n\t}\n\n\tif shardPrimary.Keyspace != tablet.Keyspace || shardPrimary.Shard != tablet.Shard {\n\t\treturn nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, \"primary %v and potential replica %v not in same keyspace shard (%v/%v)\", topoproto.TabletAliasString(shard.PrimaryAlias), topoproto.TabletAliasString(tablet.Alias), tablet.Keyspace, tablet.Shard)\n\t}\n\n\treturn shardPrimary, nil\n}\n\n// IsPrimaryTablet is a helper function to determine whether the current tablet\n// is a primary before we allow its tablet record to be deleted. The canonical\n// way to determine the only true primary in a shard is to list all the tablets\n// and find the one with the highest PrimaryTermStartTime among the ones that\n// claim to be primary.","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/topotools/tablet.go#L186-L222","documentation":"GetShardPrimaryForTablet first confirms the shard has a primary alias, then fetches the full tablet record for that alias. If the GetTablet lookup fails, the error is wrapped as 'cannot lookup primary tablet %v for shard %v/%v' with the alias, keyspace/shard, and underlying topo error, preserving the cause via %w.","triggerScenarios":"Calling GetShardPrimaryForTablet (via SetReplicationSource or reparenting flows) when the shard record lists a PrimaryAlias but the tablet record for that alias cannot be read from the topo — deleted record, topo server down, or alias corruption.","commonSituations":"The primary tablet record was manually deleted from the topo while the shard record still points to it; a topo outage during a reparent; stale shard record after the primary was decommissioned without a proper reparent.","solutions":["Fix the underlying topo lookup error (check the wrapped cause): ensure the topo server is reachable and the tablet record for the primary alias exists.","If the primary record is truly gone, run a reparenting flow (e.g. vtctldclient PlannedReparentShard or EmergencyReparentShard) to elect a valid primary and update the shard record.","Verify shard consistency with vtctldclient GetShard and reconcile stale PrimaryAlias values."],"exampleFix":"// before: no guard against missing primary record\nprimary, err := topotools.GetShardPrimaryForTablet(ctx, ts, tablet)\n// after: check shard state first\nshard, _ := ts.GetShard(ctx, tablet.Keyspace, tablet.Shard)\nif shard != nil && shard.PrimaryAlias != nil {\n    if _, err := ts.GetTablet(ctx, shard.PrimaryAlias); err != nil {\n        return fmt.Errorf(\"primary alias %v missing from topo; run a reparent\", topoproto.TabletAliasString(shard.PrimaryAlias))\n    }\n}\nprimary, err := topotools.GetShardPrimaryForTablet(ctx, ts, tablet)","handlingStrategy":"validation","validationCode":"shard, err := ts.GetShard(ctx, keyspace, shard)\nif err != nil {\n    return err\n}\nif shard.PrimaryAlias != nil {\n    if _, err := ts.GetTablet(ctx, shard.PrimaryAlias); err != nil {\n        return fmt.Errorf(\"primary %v record missing; reparent needed\",\n            topoproto.TabletAliasString(shard.PrimaryAlias))\n    }\n}","typeGuard":"func primaryRecordExists(ctx context.Context, ts topo.Server, shard *topo.ShardInfo) bool {\n    if !shard.HasPrimary() {\n        return false\n    }\n    _, err := ts.GetTablet(ctx, shard.PrimaryAlias)\n    return err == nil\n}","tryCatchPattern":"primary, err := topotools.GetShardPrimaryForTablet(ctx, ts, tablet)\nif err != nil {\n    if strings.Contains(err.Error(), \"cannot lookup primary tablet\") {\n        return fmt.Errorf(\"shard record stale/primary record missing; run reparent: %w\", err)\n    }\n    return err\n}","preventionTips":["Never delete a tablet record that is still listed as a shard primary — reparent first","Monitor shard records for primary aliases whose tablet records cannot be fetched","After decommissioning a primary, always run a reparent flow to update the shard record"],"tags":["topo","replication","primary-election"],"backgroundTag":"primary-tablet-lookup-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}