vitessio/vitess · error
shard %v/%v has no primary
Error message
shard %v/%v has no primary
What it means
getPrimaryPosition reads the shard record from the topo to find the primary tablet and fetch its replication position (used for backup validation/restore checks). If the shard's PrimaryAlias is zero — meaning no primary has ever been elected or the shard record is uninitialized — this error is returned.
Source
Thrown at go/vt/mysqlctl/builtinbackupengine.go:1833
return false
}
return true
}
// 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{}View on GitHub (pinned to 01a25a7d17)
Solutions
- Check the shard record: vtctldclient GetShard <keyspace>/<shard> — confirm PrimaryAlias is empty.
- Run InitShardPrimary (or let Orchestrator/ERT complete) to elect a primary.
- Verify you targeted the correct keyspace/shard names.
- Retry the backup/restore operation once the primary is serving.
Defensive patterns
Strategy: validation
Validate before calling
si, err := ts.GetShard(ctx, keyspace, shard)
if err != nil { return err }
if topoproto.TabletAliasIsZero(si.PrimaryAlias) {
return fmt.Errorf("shard %s/%s has no primary; run InitShardPrimary first", keyspace, shard)
} Try / catch
if err := doBackupOrRestore(...); err != nil {
if strings.Contains(err.Error(), "has no primary") {
// elect a primary via InitShardPrimary / ERS, then retry
}
} Prevention
- Never run backups against shards without an elected primary.
- Automate primary election (ERS/Orchestrator) so shards are never leaderless.
- Validate shard topology in pre-backup checks.
When it happens
Trigger: Calling backup/restore paths that call getPrimaryPosition against a keyspace/shard whose topo shard record has no PrimaryAlias set (fresh shard without InitShardPrimary, or primary term ended without a new election).
Common situations: Running vtctldclient Backup on a shard with no serving primary; shard created but InitShardPrimary never run; primary alias cleared after failures and ERS not completed.
Related errors
- no primary tablet found
- can't get primary tablet record %v: %v
- cannot get (or create) shard %v/%v: %v
- shard %v/%v has a different KeyRange: %v != %v
- old tablet has shard %v/%v. Cannot override with shard %v/%v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/0f5e8b2ef9ead51e.
Report an issue: GitHub.