vitessio/vitess · error

can't get primary tablet record %v: %v

Error message

can't get primary tablet record %v: %v

What it means

After finding the shard's PrimaryAlias, getPrimaryPosition fetches the full tablet record via ts.GetTablet. If that record cannot be read from the topo, this error wraps the alias and the underlying cause. It usually means the shard record points at a primary that no longer exists in the topo.

Source

Thrown at go/vt/mysqlctl/builtinbackupengine.go:1837

// ShouldStartMySQLAfterRestore signifies if this backup engine needs to restart MySQL once the restore is completed.
func (be *BuiltinBackupEngine) ShouldStartMySQLAfterRestore() bool {
	return true
}

func (be *BuiltinBackupEngine) Name() string { return builtinBackupEngineName }

func getPrimaryPosition(ctx context.Context, tmc tmclient.TabletManagerClient, ts *topo.Server, keyspace, shard string) (replication.Position, error) {
	si, err := ts.GetShard(ctx, keyspace, shard)
	if err != nil {
		return replication.Position{}, vterrors.Wrap(err, "can't read shard")
	}
	if topoproto.TabletAliasIsZero(si.PrimaryAlias) {
		return replication.Position{}, fmt.Errorf("shard %v/%v has no primary", keyspace, shard)
	}
	ti, err := ts.GetTablet(ctx, si.PrimaryAlias)
	if err != nil {
		return replication.Position{}, fmt.Errorf("can't get primary tablet record %v: %v", topoproto.TabletAliasString(si.PrimaryAlias), err)
	}
	posStr, err := tmc.PrimaryPosition(ctx, ti.Tablet)
	if err != nil {
		return replication.Position{}, fmt.Errorf("can't get primary replication position: %v", err)
	}
	pos, err := replication.DecodePosition(posStr)
	if err != nil {
		return replication.Position{}, fmt.Errorf("can't decode primary replication position %q: %v", posStr, err)
	}
	return pos, nil
}

func init() {
	BackupRestoreEngineMap[builtinBackupEngineName] = &BuiltinBackupEngine{}
}

// closeWithRetry does just what it says. Retrying a close operation is important as
// an error is most likely transient/ephemeral and leaving around open file descriptors

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Read the wrapped cause to see if it is a node-not-found from topo.
  2. Inspect the shard record's PrimaryAlias and compare with actual tablets (vtctldclient GetTablets).
  3. Run EmergencyReparentShard or re-initialize the shard so PrimaryAlias points to a live tablet.
  4. Prune stale tablet records from the topo and re-run the operation.
Defensive patterns

Strategy: validation

Validate before calling

si, _ := ts.GetShard(ctx, keyspace, shard)
if _, err := ts.GetTablet(ctx, si.PrimaryAlias); err != nil {
	// stale PrimaryAlias: reparent or clean topo before proceeding
}

Try / catch

if _, err := getPrimaryPosition(ctx, tmc, ts, ks, shard); err != nil {
	if strings.Contains(err.Error(), "can't get primary tablet record") {
		// refresh shard record / run ERS to fix stale alias
	}
}

Prevention

When it happens

Trigger: ts.GetTablet(ctx, si.PrimaryAlias) fails because the primary tablet record was deleted from topo (e.g. tablet fully removed after failover) while the shard record still references the stale alias.

Common situations: Stale PrimaryAlias after a primary was deleted or rebuilt; topo backend inconsistency (etcd/zookeeper) after partial failover; typo'd cell in tablet record cleanup.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/9d6aa41ad027fd3d. Report an issue: GitHub.