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

  1. Log the raw response body to see what the endpoint actually returned.
  2. Verify the base URL targets genuine Prometheus and any proxy passes /api/v1/status/buildinfo through unmodified.
  3. Bypass intermediary caches/gateways to test the endpoint directly with curl.
  4. 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

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


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)