{"record":{"id":"cfc1d00a55d8525b","repo":"thanos-io/thanos","slug":"unmarshal-build-info-api-response","errorCode":null,"errorMessage":"unmarshal build info API response","messagePattern":"unmarshal build info API response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/promclient/promclient.go","lineNumber":691,"sourceCode":"\tbody, code, err := c.req2xx(ctx, &u, http.MethodGet, nil)\n\tif err != nil {\n\t\tif code == http.StatusNotFound {\n\t\t\treturn \"0\", nil\n\t\t}\n\t\tif code == http.StatusMethodNotAllowed {\n\t\t\treturn \"0\", nil\n\t\t}\n\t\treturn \"\", err\n\t}\n\n\tvar b struct {\n\t\tData struct {\n\t\t\tVersion string `json:\"version\"`\n\t\t} `json:\"data\"`\n\t}\n\n\tif err = json.Unmarshal(body, &b); err != nil {\n\t\treturn \"\", errors.Wrap(err, \"unmarshal build info API response\")\n\t}\n\n\treturn b.Data.Version, nil\n}\n\n// LowestTimestamp returns the lowest timestamp in the TSDB by parsing the /metrics endpoint\n// and extracting the prometheus_tsdb_lowest_timestamp_seconds metric from it.\nfunc (c *Client) LowestTimestamp(ctx context.Context, base *url.URL) (int64, error) {\n\tu := *base\n\tu.Path = path.Join(u.Path, \"/metrics\")\n\n\tlevel.Debug(c.logger).Log(\"msg\", \"lowest timestamp\", \"url\", u.String())\n\n\treq, err := http.NewRequest(http.MethodGet, u.String(), nil)\n\tif err != nil {\n\t\treturn 0, errors.Wrap(err, \"create request\")\n\t}\n","sourceCodeStart":673,"sourceCodeEnd":709,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/promclient/promclient.go#L673-L709","documentation":"BuildVersion fetches /api/v1/status/buildinfo and decodes the body into {data:{version:string}}. This error wraps json.Unmarshal failing when the 2xx body is not valid JSON or does not match that structure. Note the endpoint only exists on Prometheus >= 2.14.0; older versions yield 404/405 which are handled earlier and return \"0\" instead of this error.","triggerScenarios":"Client.BuildVersion receives a 2xx response from /api/v1/status/buildinfo whose body fails json.Unmarshal into the buildinfo envelope — non-JSON body, data not an object, version of wrong type.","commonSituations":"A proxy/SSO gateway returning an HTML page with status 200, hitting a Thanos/other endpoint that answers buildinfo with a different schema, or response-rewriting middleware.","solutions":["Log the raw response body to see what the endpoint actually returned.","Verify the base URL targets genuine Prometheus and any proxy passes /api/v1/status/buildinfo through unmodified.","Bypass intermediary caches/gateways to test the endpoint directly with curl.","If targeting Prometheus < 2.14.0, rely on the client's built-in 404/405 -> \"0\" handling rather than modifying the endpoint."],"exampleFix":"// before: buildinfo passing through a rewriting proxy\nhttps://gateway.example.com/prom  // returns HTML 200\n// after: direct Prometheus service\nhttp://prometheus:9090","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"version, err := client.BuildVersion(ctx, u)\nif err != nil {\n    if strings.Contains(err.Error(), \"unmarshal build info API response\") {\n        log.Warn(\"buildinfo response not parseable; assuming old Prometheus\")\n        version = \"0\" // fallback like the built-in 404/405 path\n    } else {\n        return err\n    }\n}","preventionTips":["Ensure proxies pass /api/v1/status/buildinfo through unmodified","Treat buildinfo as optional: handle 404/405 and parse failures as \"unknown version\"","Confirm the target is genuine Prometheus >= 2.14.0 before relying on the version value"],"tags":["json","prometheus","unmarshal","buildinfo"],"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"}