{"record":{"id":"1a7a5c49716ba4b9","repo":"vitessio/vitess","slug":"can-t-lock-shard-keyspace-is-unspecified","errorCode":null,"errorMessage":"can't lock shard: keyspace is unspecified","messagePattern":"can't lock shard: keyspace is unspecified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtorc/logic/topology_recovery.go","lineNumber":243,"sourceCode":"\tstats.NewGaugeFunc(\"ShardLocksActive\", \"Number of actively-held shard locks\", func() int64 {\n\t\treturn shardsLockCounter.Load()\n\t})\n\turgentOperations = cache.New(urgentOperationsInterval, 2*urgentOperationsInterval)\n\tgo initializeTopologyRecoveryPostConfiguration()\n}\n\nfunc initializeTopologyRecoveryPostConfiguration() {\n\tconfig.WaitForConfigurationToBeLoaded()\n}\n\nfunc getLockAction(tabletAlias *topodatapb.TabletAlias, code inst.AnalysisCode) string {\n\treturn fmt.Sprintf(\"VTOrc Recovery for %v on %v\", code, topoproto.TabletAliasString(tabletAlias))\n}\n\n// LockShard locks the keyspace-shard preventing others from performing conflicting actions.\nfunc LockShard(ctx context.Context, keyspace, shard, lockAction string) (context.Context, func(*error), error) {\n\tif keyspace == \"\" {\n\t\treturn nil, nil, errors.New(\"can't lock shard: keyspace is unspecified\")\n\t}\n\tif shard == \"\" {\n\t\treturn nil, nil, errors.New(\"can't lock shard: shard name is unspecified\")\n\t}\n\tif hasReceivedSIGTERM.Load() > 0 {\n\t\treturn nil, nil, errors.New(\"can't lock shard: SIGTERM received\")\n\t}\n\n\tstartTime := time.Now()\n\tdefer func() {\n\t\tlockTime := time.Since(startTime)\n\t\tshardLockTimings.Add(\"Lock\", lockTime)\n\t}()\n\n\tshardsLockCounter.Add(1)\n\tctx, unlock, err := ts.TryLockShard(ctx, keyspace, shard, lockAction)\n\tif err != nil {\n\t\tshardsLockCounter.Add(-1)","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtorc/logic/topology_recovery.go#L225-L261","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the instance/tablet record has a valid keyspace before triggering recoveries (fix discovery/analysis).","Check code that parses keyspace/shard names — verify it handles fully-qualified names correctly.","Guard call sites: skip locking/recovery when keyspace is empty and log the anomaly."],"exampleFix":"// before\nctx, unlock, err := logic.LockShard(ctx, keyspace, shard, action)\n// after\nif keyspace == \"\" || shard == \"\" {\n    return fmt.Errorf(\"cannot lock shard %q/%q: incomplete identifiers\", keyspace, shard)\n}\nctx, unlock, err := logic.LockShard(ctx, keyspace, shard, action)","handlingStrategy":"validation","validationCode":"if keyspace == \"\" {\n    return errors.New(\"can't lock shard: keyspace is unspecified\")\n}\nif shard == \"\" {\n    return errors.New(\"can't lock shard: shard name is unspecified\")\n}","typeGuard":"func lockableShard(keyspace, shard string) bool {\n    return keyspace != \"\" && shard != \"\"\n}","tryCatchPattern":"ctx, unlock, err := logic.LockShard(ctx, keyspace, shard, action)\nif err != nil {\n    return fmt.Errorf(\"failed to acquire shard lock for %s/%s: %w\", keyspace, shard, err)\n}\ndefer func() { unlock(&recoverErr) }()","preventionTips":["Validate keyspace/shard fields on instance records before recovery actions.","Fix name-splitting code that derives keyspace and shard from qualified names.","Always check LockShard's error before using the returned unlock function.","Skip recoveries for tablets whose keyspace/shard metadata is incomplete."],"tags":["vtorc","shard-lock","validation","empty-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}