{"record":{"id":"4d861c124a1d8e32","repo":"thanos-io/thanos","slug":"could-not-unmarshal-parameter-s","errorCode":null,"errorMessage":"could not unmarshal parameter %s","messagePattern":"could not unmarshal parameter (.+?)","errorType":"validation","errorClass":"api.ApiError","httpStatus":400,"severity":"error","filePath":"pkg/api/query/v1.go","lineNumber":428,"sourceCode":"\t}\n\t// Default step is used this way to make it consistent with UI.\n\td := time.Duration(math.Max(float64(rangeSeconds/250), float64(defaultRangeQueryStep/time.Second))) * time.Second\n\treturn d, nil\n}\n\nfunc (qapi *QueryAPI) parseShardInfo(r *http.Request) (*storepb.ShardInfo, *api.ApiError) {\n\tdata := r.FormValue(ShardInfoParam)\n\tif data == \"\" {\n\t\treturn nil, nil\n\t}\n\n\tif len(data) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tvar info storepb.ShardInfo\n\tif err := json.Unmarshal([]byte(data), &info); err != nil {\n\t\treturn nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, \"could not unmarshal parameter %s\", ShardInfoParam)}\n\t}\n\n\treturn &info, nil\n}\n\nfunc (qapi *QueryAPI) getQueryExplain(query promql.Query) (*engine.ExplainOutputNode, *api.ApiError) {\n\tif eq, ok := query.(engine.ExplainableQuery); ok {\n\t\treturn eq.Explain(), nil\n\t}\n\treturn nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf(\"Query not explainable\")}\n}\n\nfunc (qapi *QueryAPI) parseQueryAnalyzeParam(r *http.Request) bool {\n\treturn (r.FormValue(QueryAnalyzeParam) == \"true\" || r.FormValue(QueryAnalyzeParam) == \"1\")\n}\n\nfunc analyzeQueryOutput(query promql.Query, engineType PromqlEngineType, tracker *fanout.Tracker) (queryTelemetry, error) {\n\tif eq, ok := query.(engine.ExplainableQuery); ok {","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/api/query/v1.go#L410-L446","documentation":"parseShardInfo reads the `shard_info` query parameter and JSON-unmarshals it into storepb.ShardInfo. When the parameter is present but is not valid JSON (or does not match the ShardInfo schema), the API returns an HTTP 400 (api.ErrorBadData) wrapping the unmarshal error with the parameter name.","triggerScenarios":"Calling /api/v1/query or /api/v1/query_range (or their explain variants) with `shard_info` set to malformed JSON, e.g. shard_info={\"shard_index\":}, or a non-object value like shard_info=abc.","commonSituations":"Downstream Thanos Store/Query gateways forwarding shard info between query nodes with URL-encoding issues (raw `{`/`}` not percent-encoded); clients manually constructing shard_info JSON with wrong field types (string instead of int).","solutions":["URL-encode the shard_info JSON value when building the request (e.g. %7B%22shard_index%22%3A0%7D).","Verify the JSON matches storepb.ShardInfo fields (shard_index, total_shards as numbers).","Omit the shard_info parameter if sharding is not in use (empty value is accepted and treated as nil)."],"exampleFix":"// before\nGET /api/v1/query?query=up&shard_info={\"shard_index\":0,\"total_shards\":2}\n// after\nGET /api/v1/query?query=up&shard_info=%7B%22shard_index%22%3A0%2C%22total_shards%22%3A2%7D","handlingStrategy":"validation","validationCode":"if (shardInfo) {\n  const parsed = JSON.parse(JSON.stringify(shardInfo)); // throws on invalid input\n  if (!Number.isInteger(parsed.shard_index) || !Number.isInteger(parsed.total_shards)) {\n    throw new Error('shard_info must contain integer shard_index and total_shards');\n  }\n  url.searchParams.set('shard_info', JSON.stringify(parsed)); // auto URL-encodes\n}","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetch(url);\n  const body = await res.json();\n  if (body.status === 'error' && /could not unmarshal parameter shard_info/.test(body.error)) {\n    // log the raw shard_info value and re-serialize it\n  }\n} catch (err) {}","preventionTips":["Build shard_info with JSON.stringify and let the HTTP client URL-encode it; never hand-write the JSON into URLs.","Keep shard_index/total_shards as JSON numbers, not strings.","Omit the parameter when sharding is not used."],"tags":["http-api","json","bad-request","query-parameter"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}