{"record":{"id":"5dc867a8345238db","repo":"vitessio/vitess","slug":"w-parsing-s-at-position-d","errorCode":null,"errorMessage":"%w: parsing %s at position %d","messagePattern":"%w: parsing (.+?) at position (.+?)","errorType":"http","errorClass":"errors.BadRequest","httpStatus":400,"severity":"error","filePath":"go/vt/vtadmin/http/shards.go","lineNumber":79,"sourceCode":"\tvars := mux.Vars(r.Request)\n\trecursive, err := r.ParseQueryParamAsBool(\"recursive\", false)\n\tif err != nil {\n\t\treturn NewJSONResponse(nil, err)\n\t}\n\n\tevenIfServing, err := r.ParseQueryParamAsBool(\"even_if_serving\", false)\n\tif err != nil {\n\t\treturn NewJSONResponse(nil, err)\n\t}\n\n\tshardList := r.URL.Query()[\"keyspace_shard\"]\n\tshardList = sets.List(sets.New(shardList...))\n\tshards := make([]*vtctldatapb.Shard, len(shardList))\n\tfor i, kss := range shardList {\n\t\tks, shard, err := topoproto.ParseKeyspaceShard(kss)\n\t\tif err != nil {\n\t\t\treturn NewJSONResponse(nil, &errors.BadRequest{\n\t\t\t\tErr: fmt.Errorf(\"%w: parsing %s at position %d\", err, kss, i),\n\t\t\t})\n\t\t}\n\n\t\tshards[i] = &vtctldatapb.Shard{\n\t\t\tKeyspace: ks,\n\t\t\tName:     shard,\n\t\t\tShard:    &topodatapb.Shard{},\n\t\t}\n\t}\n\n\tif len(shards) == 0 {\n\t\treturn NewJSONResponse(nil, &errors.BadRequest{\n\t\t\tErr: fmt.Errorf(\"must specify at least one keyspace_shard to delete (got %+v)\", shardList),\n\t\t})\n\t}\n\n\tresp, err := api.server.DeleteShards(ctx, &vtadminpb.DeleteShardsRequest{\n\t\tClusterId: vars[\"cluster_id\"],","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/http/shards.go#L61-L97","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfetch(`/api/shards/delete?keyspace_shard=${ks}`) // ks = \"commerce-0\"\n// after\nconst ksShard = `${keyspace}/${shard}` // \"commerce/0\"\nfetch(`/api/shards/delete?keyspace_shard=${encodeURIComponent(ksShard)}`)","handlingStrategy":"validation","validationCode":"for i, ksShard := range keyspaceShards {\n\tif _, _, err := topoproto.ParseKeyspaceShard(ksShard); err != nil {\n\t\treturn fmt.Errorf(\"invalid keyspace_shard %q at index %d\", ksShard, i)\n\t}\n}","typeGuard":"func isKeyspaceShard(s string) bool {\n\tparts := strings.Split(s, \"/\")\n\treturn len(parts) == 2 && parts[0] != \"\" && parts[1] != \"\"\n}","tryCatchPattern":"resp, err := http.Get(u)\nif err != nil {\n\treturn err\n}\nif resp.StatusCode == http.StatusBadRequest {\n\tvar e vtadminErr\n\t_ = json.NewDecoder(resp.Body).Decode(&e)\n\treturn fmt.Errorf(\"delete-shards rejected: %v\", e)\n}","preventionTips":["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."],"tags":["http","bad-request","parsing","vtadmin"],"backgroundTag":"invalid-keyspace-shard","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}