vitessio/vitess · error · ErrNoPrimaryTablet

no primary tablet found

Error message

no primary tablet found

What it means

ErrNoPrimaryTablet is the sentinel returned by shardPrimary when a shard has no elected primary tablet. It signals the shard's primary alias is empty in the topo record, so primary-dependent operations cannot proceed.

Source

Thrown at go/vt/vtorc/logic/tablet_discovery.go:65

var (
	ts               *topo.Server
	tmc              tmclient.TabletManagerClient
	clustersToWatch  []string
	cellsNoRecovery  []string
	shutdownWaitTime = 30 * time.Second
	// cellsNoRecoveryValidated is true once validateCellsNoRecovery has confirmed
	// every entry in cellsNoRecovery exists in the topology. It starts false when
	// the flag is set but the topo was unreachable at startup; recovery is blocked
	// until a subsequent refresh cycle can complete validation.
	cellsNoRecoveryValidated atomic.Bool
	// shardsToWatch is a map storing the shards for a given keyspace that need to be watched.
	// We store the key range for all the shards that we want to watch.
	// This is populated by parsing `--clusters_to_watch` flag.
	shardsToWatch map[string][]*topodatapb.KeyRange

	// ErrNoPrimaryTablet is a fixed error message.
	ErrNoPrimaryTablet = errors.New("no primary tablet found")
)

func init() {
	stats.NewGaugesFuncWithMultiLabels(
		"TabletsWatchedByCell",
		"Number of tablets watched by cell",
		[]string{"Cell"},
		getTabletsWatchedByCellStats,
	)
	stats.NewGaugesFuncWithMultiLabels(
		"TabletsWatchedByShard",
		"Number of tablets watched by keyspace/shard",
		[]string{"Keyspace", "Shard"},
		getTabletsWatchedByShardStats,
	)
	stats.NewGaugesFuncWithMultiLabels(
		"EmergencyReparentShardDisabled",
		"Shards with EmergencyReparentShard disabled by keyspace/shard (1 = disabled)",

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Elect a primary: vtctldclient PlannedReparentShard or EmergencyReparentShard for the keyspace/shard.
  2. Check tablet health and replication status if the primary election failed.
  3. Wait and retry — during an in-flight reparent the primary record is temporarily empty; vtorc retries on subsequent ticks.

Example fix

// before
prim, err := shardPrimary(ctx, keyspace, shard)
if err != nil { return err }
// after
prim, err := shardPrimary(ctx, keyspace, shard)
if errors.Is(err, ErrNoPrimaryTablet) {
    return fmt.Errorf("shard %s/%s has no primary; run PlannedReparentShard first", keyspace, shard)
} else if err != nil { return err }
Defensive patterns

Strategy: retry

Validate before calling

// before primary-dependent work
shardInfo, err := ts.GetShard(ctx, keyspace, shard)
if err != nil { return err }
if shardInfo.GetPrimaryAlias() == nil {
    return ErrNoPrimaryTablet
}

Type guard

func shardHasPrimary(si *topo.ShardInfo) bool {
    return si != nil && si.GetPrimaryAlias() != nil
}

Try / catch

prim, err := shardPrimary(ctx, keyspace, shard)
if errors.Is(err, ErrNoPrimaryTablet) {
    // wait for reparent / election to finish, retry next tick
    return nil
} else if err != nil { return err }

Prevention

When it happens

Trigger: shardPrimary lookup for a keyspace/shard whose record has no primary — during initial cluster setup, after a failed PrimaryElect, or while reparenting is in flight.

Common situations: Freshly created shard before InitShardPrimary; primary tablet down mid-reparenting leaving the record unset; vtorc scanning a shard concurrently with vtctl reparent operations.

Related errors


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