thanos-io/thanos · error

unmarshal query instant response

Error message

unmarshal query instant response

What it means

This error is thrown when the HTTP 200 body returned by Prometheus for an instant query cannot be parsed as JSON. QueryInstant unmarshals the response into a struct with Data, ResultType, Error, ErrorType and Warnings fields; a body that is not valid JSON (or wrong Content-Type, e.g. an HTML error page) makes json.Unmarshal fail. It signals the server replied 2xx but with a body that is not the expected API JSON envelope.

Solutions

  1. Verify the URL targets the JSON API path (/api/v1/query), not the web UI or a redirect target
  2. curl the same query and inspect the Content-Type and raw body (expect application/json)
  3. Check any proxy/gateway/auth layer is not injecting HTML pages with status 200
  4. Confirm the server is actually Prometheus exposing the v1 query API
  5. Log the raw body on this error to diagnose exactly what was returned

Example fix

// before
resp, err := http.Get("https://prometheus.example.com/") // returns HTML page -> unmarshal query instant response
// after
resp, err := http.Get("https://prometheus.example.com/api/v1/query?query=up")
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: confirm the endpoint returns JSON
resp, err := http.Get(baseURL + "/api/v1/query?query=up")
if err != nil { return err }
if ct := resp.Header.Get("Content-Type"); !strings.Contains(ct, "application/json") {
    return fmt.Errorf("endpoint returned %q, not JSON", ct)
}

Try / catch

_, _, _, err := client.PromqlQueryInstant(ctx, opts)
var perr *json.SyntaxError
if err != nil && errors.As(errors.Cause(err), &perr) {
    return fmt.Errorf("non-JSON response body at offset %d; check proxy/UI URL", perr.Offset)
}

Prevention

When it happens

Trigger: PromqlQueryInstant receives a 200 response whose body is not valid JSON: an HTML login/proxy page, a truncated response, wrong Content-Type from a misconfigured proxy, or the endpoint returning plaintext (e.g. targeting the UI page instead of /api/v1/query).

Common situations: Reverse proxy or auth gateway returning an HTML page with 200; pointing the client at the Prometheus web UI root instead of the API path; custom middleware modifying the response body; Prometheus behind a gateway that strips or corrupts the payload.

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/b75c2a6014d0422e. Report an issue: GitHub.

Appendix: source

Thrown at pkg/promclient/promclient.go:475

	}

	// Decode only ResultType and load Result only as RawJson since we don't know
	// structure of the Result yet.
	var m struct {
		Data struct {
			ResultType  string          `json:"resultType"`
			Result      json.RawMessage `json:"result"`
			Explanation *Explanation    `json:"explanation,omitempty"`
		} `json:"data"`

		Error     string `json:"error,omitempty"`
		ErrorType string `json:"errorType,omitempty"`
		// Extra fields supported by Thanos Querier.
		Warnings []string `json:"warnings"`
	}

	if err = json.Unmarshal(body, &m); err != nil {
		return nil, nil, nil, errors.Wrap(err, "unmarshal query instant response")
	}

	var vectorResult model.Vector

	// Decode the Result depending on the ResultType
	// Currently only `vector` and `scalar` types are supported.
	switch m.Data.ResultType {
	case string(parser.ValueTypeVector):
		if err = json.Unmarshal(m.Data.Result, &vectorResult); err != nil {
			return nil, nil, nil, errors.Wrap(err, "decode result into ValueTypeVector")
		}
	case string(parser.ValueTypeScalar):
		vectorResult, err = convertScalarJSONToVector(m.Data.Result)
		if err != nil {
			return nil, nil, nil, errors.Wrap(err, "decode result into ValueTypeScalar")
		}
	default:
		if m.Warnings != nil {

View on GitHub (pinned to 35b8b99117)