vitessio/vitess · error · errors.BadRequest

must specify at least one keyspace_shard to delete (got %+v)

Error message

must specify at least one keyspace_shard to delete (got %+v)

What it means

DeleteShards requires at least one shard to operate on; if the parsed shard list is empty, the handler returns a 400 BadRequest telling the caller to specify at least one keyspace_shard. This guards the vtctld DeleteShards RPC, which would otherwise fail downstream, by rejecting the request early with a clear message.

Source

Thrown at go/vt/vtadmin/http/shards.go:92

	shards := make([]*vtctldatapb.Shard, len(shardList))
	for i, kss := range shardList {
		ks, shard, err := topoproto.ParseKeyspaceShard(kss)
		if err != nil {
			return NewJSONResponse(nil, &errors.BadRequest{
				Err: fmt.Errorf("%w: parsing %s at position %d", err, kss, i),
			})
		}

		shards[i] = &vtctldatapb.Shard{
			Keyspace: ks,
			Name:     shard,
			Shard:    &topodatapb.Shard{},
		}
	}

	if len(shards) == 0 {
		return NewJSONResponse(nil, &errors.BadRequest{
			Err: fmt.Errorf("must specify at least one keyspace_shard to delete (got %+v)", shardList),
		})
	}

	resp, err := api.server.DeleteShards(ctx, &vtadminpb.DeleteShardsRequest{
		ClusterId: vars["cluster_id"],
		Options: &vtctldatapb.DeleteShardsRequest{
			Shards:        shards,
			Recursive:     recursive,
			EvenIfServing: evenIfServing,
		},
	})
	return NewJSONResponse(resp, err)
}

// EmergencyFailoverShard implements the http wrapper for
// POST /shard/{cluster_id}/{keyspace}/{shard}/emergency_failover.
//
// Query params: none

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Include at least one valid keyspace_shard query parameter, e.g. ?keyspace_shard=commerce/0.
  2. Client-side: check the selected shard list is non-empty before issuing the request.
  3. Filter out empty strings before sending so blank entries don't produce a request with no real targets.

Example fix

// before
const qs = shards.map(s => `keyspace_shard=${s}`).join('&')
// after
if (shards.length === 0) throw new Error('select at least one shard')
const qs = shards.map(s => `keyspace_shard=${encodeURIComponent(s)}`).join('&')
Defensive patterns

Strategy: validation

Validate before calling

shards := nonEmpty(keyspaceShards)
if len(shards) == 0 {
	return errors.New("must provide at least one keyspace_shard")
}

Try / catch

resp, err := http.Post(u, "application/json", body)
if err == nil && resp.StatusCode == 400 {
	var e vtadminErr
	_ = json.NewDecoder(resp.Body).Decode(&e)
	return fmt.Errorf("request invalid: %v", e)
}

Prevention

When it happens

Trigger: Calling the delete-shards endpoint without any `keyspace_shard` query parameters, or with only empty values such that the parsed shard list is zero-length.

Common situations: Client omits the query parameter entirely; UI sends an empty selection; list built from a split of an empty string producing an empty/blank list.

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/95a3501ddea30066. Report an issue: GitHub.