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

  1. Check the shard record: vtctldclient GetShard <keyspace>/<shard> — confirm PrimaryAlias is empty.
  2. Run InitShardPrimary (or let Orchestrator/ERT complete) to elect a primary.
  3. Verify you targeted the correct keyspace/shard names.
  4. 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

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


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