vitessio/vitess · error
failed to lock %s; if you really want to delete this keyspac
Error message
failed to lock %s; if you really want to delete this keyspace, re-run with Force=true: %w
What it means
DeleteKeyspace acquires a keyspace lock to serialize against other workflows. If locking fails and Force is false, the delete is refused with this message telling the operator to re-run with Force=true. With Force=true, the lock failure is only logged and deletion proceeds unsafely.
Source
Thrown at go/vt/vtctl/grpcvtctldserver/server.go:1146
}
// DeleteKeyspace is part of the vtctlservicepb.VtctldServer interface.
func (s *VtctldServer) DeleteKeyspace(ctx context.Context, req *vtctldatapb.DeleteKeyspaceRequest) (resp *vtctldatapb.DeleteKeyspaceResponse, err error) {
span, ctx := trace.NewSpan(ctx, "VtctldServer.DeleteKeyspace")
defer span.Finish()
defer panicHandler(&err)
span.Annotate("keyspace", req.Keyspace)
span.Annotate("recursive", req.Recursive)
span.Annotate("force", req.Force)
lctx, unlock, lerr := s.ts.LockKeyspace(ctx, req.Keyspace, "DeleteKeyspace")
switch {
case lerr == nil:
ctx = lctx
case !req.Force:
err = fmt.Errorf("failed to lock %s; if you really want to delete this keyspace, re-run with Force=true: %w", req.Keyspace, lerr)
return nil, err
default:
log.Warn(fmt.Sprintf("%s: failed to lock keyspace %s for deletion, but force=true, proceeding anyway ...", lerr, req.Keyspace))
}
if unlock != nil {
defer func() {
// Attempting to unlock a keyspace we successfully deleted results
// in ts.unlockKeyspace returning an error, which can make the
// overall RPC _seem_ like it failed.
//
// So, we do this extra checking to allow for specifically this
// scenario to result in "success."
origErr := err
unlock(&err)
if origErr == nil && topo.IsErrType(err, topo.NoNode) {
err = nil
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Wait for the holding workflow to finish, then retry DeleteKeyspace without Force
- Find and clean up stale locks (check topo lock paths / workflow status) if no workflow is actually running
- Re-run with Force=true only when certain no workflow is active, accepting the risk of concurrent modification
Defensive patterns
Strategy: validation
Validate before calling
ks, err := client.GetKeyspace(ctx, name)
if err != nil {
return fmt.Errorf("keyspace state unknown: %w", err)
}
// confirm no active workflows (Reshard/MoveTables) before deleting Try / catch
_, err := client.DeleteKeyspace(ctx, req)
if err != nil && strings.Contains(err.Error(), "failed to lock") {
// find lock holder or wait; only use Force after verifying no workflow
} Prevention
- Check for in-flight Reshard/MoveTables workflows before deleting
- Never blindly pass Force=true in automation
- Clear stale locks from crashed workflows before retrying
- Serialize keyspace deletions through a single operator/CI job
When it happens
Trigger: Calling DeleteKeyspace while another workflow holds the keyspace lock (e.g. a running Reshard, MoveTables, or another vtctld operation), or the lock cannot be taken due to topo errors, when Force is not set.
Common situations: Deleting a keyspace while a migration is in flight; a stale lock from a crashed workflow; concurrent operator actions in a shared cluster.
Related errors
- unknown keyspace type %v
- SaveVSchema(%v) = %w
- cannot delete shard %v/%v: %w
- failed to get source keyspace vschema: %v
- invalid joined path
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/98018d1ecfab0220.
Report an issue: GitHub.