thanos-io/thanos · error
unmarshal build info API response
Error message
unmarshal build info API response
What it means
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.
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.
Example fix
// before: buildinfo passing through a rewriting proxy https://gateway.example.com/prom // returns HTML 200 // after: direct Prometheus service http://prometheus:9090
Defensive patterns
Strategy: fallback
Try / catch
version, err := client.BuildVersion(ctx, u)
if err != nil {
if strings.Contains(err.Error(), "unmarshal build info API response") {
log.Warn("buildinfo response not parseable; assuming old Prometheus")
version = "0" // fallback like the built-in 404/405 path
} else {
return err
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- unmarshal response
- unmarshal query instant response
- unmarshal query range response
- decode result into ValueTypeMatrix
- unmarshal marker JSON
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/cfc1d00a55d8525b.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/promclient/promclient.go:691
body, code, err := c.req2xx(ctx, &u, http.MethodGet, nil)
if err != nil {
if code == http.StatusNotFound {
return "0", nil
}
if code == http.StatusMethodNotAllowed {
return "0", nil
}
return "", err
}
var b struct {
Data struct {
Version string `json:"version"`
} `json:"data"`
}
if err = json.Unmarshal(body, &b); err != nil {
return "", errors.Wrap(err, "unmarshal build info API response")
}
return b.Data.Version, nil
}
// LowestTimestamp returns the lowest timestamp in the TSDB by parsing the /metrics endpoint
// and extracting the prometheus_tsdb_lowest_timestamp_seconds metric from it.
func (c *Client) LowestTimestamp(ctx context.Context, base *url.URL) (int64, error) {
u := *base
u.Path = path.Join(u.Path, "/metrics")
level.Debug(c.logger).Log("msg", "lowest timestamp", "url", u.String())
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil {
return 0, errors.Wrap(err, "create request")
}
View on GitHub (pinned to 35b8b99117)