vitessio/vitess · error

can't lock shard: keyspace is unspecified

Error message

can't lock shard: keyspace is unspecified

What it means

LockShard takes a shard-level lock to prevent conflicting recovery actions and validates inputs plus process state first. This error means the keyspace parameter was empty, so a shard lock cannot be scoped — the operation is refused before acquiring any lock.

Source

Thrown at go/vt/vtorc/logic/topology_recovery.go:243

	stats.NewGaugeFunc("ShardLocksActive", "Number of actively-held shard locks", func() int64 {
		return shardsLockCounter.Load()
	})
	urgentOperations = cache.New(urgentOperationsInterval, 2*urgentOperationsInterval)
	go initializeTopologyRecoveryPostConfiguration()
}

func initializeTopologyRecoveryPostConfiguration() {
	config.WaitForConfigurationToBeLoaded()
}

func getLockAction(tabletAlias *topodatapb.TabletAlias, code inst.AnalysisCode) string {
	return fmt.Sprintf("VTOrc Recovery for %v on %v", code, topoproto.TabletAliasString(tabletAlias))
}

// LockShard locks the keyspace-shard preventing others from performing conflicting actions.
func LockShard(ctx context.Context, keyspace, shard, lockAction string) (context.Context, func(*error), error) {
	if keyspace == "" {
		return nil, nil, errors.New("can't lock shard: keyspace is unspecified")
	}
	if shard == "" {
		return nil, nil, errors.New("can't lock shard: shard name is unspecified")
	}
	if hasReceivedSIGTERM.Load() > 0 {
		return nil, nil, errors.New("can't lock shard: SIGTERM received")
	}

	startTime := time.Now()
	defer func() {
		lockTime := time.Since(startTime)
		shardLockTimings.Add("Lock", lockTime)
	}()

	shardsLockCounter.Add(1)
	ctx, unlock, err := ts.TryLockShard(ctx, keyspace, shard, lockAction)
	if err != nil {
		shardsLockCounter.Add(-1)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Ensure the instance/tablet record has a valid keyspace before triggering recoveries (fix discovery/analysis).
  2. Check code that parses keyspace/shard names — verify it handles fully-qualified names correctly.
  3. Guard call sites: skip locking/recovery when keyspace is empty and log the anomaly.

Example fix

// before
ctx, unlock, err := logic.LockShard(ctx, keyspace, shard, action)
// after
if keyspace == "" || shard == "" {
    return fmt.Errorf("cannot lock shard %q/%q: incomplete identifiers", keyspace, shard)
}
ctx, unlock, err := logic.LockShard(ctx, keyspace, shard, action)
Defensive patterns

Strategy: validation

Validate before calling

if keyspace == "" {
    return errors.New("can't lock shard: keyspace is unspecified")
}
if shard == "" {
    return errors.New("can't lock shard: shard name is unspecified")
}

Type guard

func lockableShard(keyspace, shard string) bool {
    return keyspace != "" && shard != ""
}

Try / catch

ctx, unlock, err := logic.LockShard(ctx, keyspace, shard, action)
if err != nil {
    return fmt.Errorf("failed to acquire shard lock for %s/%s: %w", keyspace, shard, err)
}
defer func() { unlock(&recoverErr) }()

Prevention

When it happens

Trigger: LockShard(ctx, "", shard, action) — called by executeCheckAndRecoverFunction paths where the keyspace was not populated, e.g., a tablet/instance record with an empty keyspace field or an unbuilt keyspace/shard string.

Common situations: Recovery acting on a tablet record whose Keyspace field is empty (tablet not fully analyzed/discovered); a bug in code that splits keyspace/shard out of a fully-qualified name; running recoveries before keyspace discovery completes.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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