vitessio/vitess · error · errors.BadRequest
%w: parsing %s at position %d
Error message
%w: parsing %s at position %d
What it means
The DeleteShards HTTP handler accepts `keyspace_shard` query parameters as "keyspace/shard" strings and parses each with ParseKeyspaceShard. When any entry is malformed, it returns a 400 BadRequest wrapping the parse error plus the offending string and its index in the list. It exists to give the client a precise indication of which list element failed.
Source
Thrown at go/vt/vtadmin/http/shards.go:79
vars := mux.Vars(r.Request)
recursive, err := r.ParseQueryParamAsBool("recursive", false)
if err != nil {
return NewJSONResponse(nil, err)
}
evenIfServing, err := r.ParseQueryParamAsBool("even_if_serving", false)
if err != nil {
return NewJSONResponse(nil, err)
}
shardList := r.URL.Query()["keyspace_shard"]
shardList = sets.List(sets.New(shardList...))
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"],View on GitHub (pinned to 01a25a7d17)
Solutions
- Fix the client to send valid keyspace/shard strings like "commerce/0".
- Validate each entry with topoproto.ParseKeyspaceShard on the client side before calling the API.
- Trim/split query lists carefully to avoid empty segments reaching the endpoint.
- Read the error's 'at position %d' field to find which list element to correct.
Example fix
// before
fetch(`/api/shards/delete?keyspace_shard=${ks}`) // ks = "commerce-0"
// after
const ksShard = `${keyspace}/${shard}` // "commerce/0"
fetch(`/api/shards/delete?keyspace_shard=${encodeURIComponent(ksShard)}`) Defensive patterns
Strategy: validation
Validate before calling
for i, ksShard := range keyspaceShards {
if _, _, err := topoproto.ParseKeyspaceShard(ksShard); err != nil {
return fmt.Errorf("invalid keyspace_shard %q at index %d", ksShard, i)
}
} Type guard
func isKeyspaceShard(s string) bool {
parts := strings.Split(s, "/")
return len(parts) == 2 && parts[0] != "" && parts[1] != ""
} Try / catch
resp, err := http.Get(u)
if err != nil {
return err
}
if resp.StatusCode == http.StatusBadRequest {
var e vtadminErr
_ = json.NewDecoder(resp.Body).Decode(&e)
return fmt.Errorf("delete-shards rejected: %v", e)
} Prevention
- Always format shard identifiers as "keyspace/shard" and URL-encode them.
- Validate entries client-side with ParseKeyspaceShard before calling the endpoint.
- Trim and filter empty items when building lists from UI selections.
When it happens
Trigger: GET/POST to the delete-shards endpoint with a keyspace_shard value that has no '/' separator, is empty, has too many parts (a/b/c), or is otherwise rejected by topoproto.ParseKeyspaceShard.
Common situations: API clients URL-encoding or quoting incorrectly; passing tablet-style keys ("keyspace shard" or fully qualified tablet paths) instead of keyspace/shard; empty strings in a comma-split list.
Related errors
- must specify at least one keyspace_shard to delete (got %+v)
- failed to parse tablet_alias %s: %w
- error parsing %s: %w
- http server stopped: %w
- no route variable found with name %s
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/5dc867a8345238db.
Report an issue: GitHub.