thanos-io/thanos · error

unable to create request

Error message

unable to create request

What it means

After building the URL (base + /api/v1/read), startPromRemoteRead creates the POST http.Request via http.NewRequest. If the URL is invalid or malformed, the wrapped error "unable to create request" is returned. This almost always means the store's configured base address is not a valid absolute HTTP URL.

Solutions

  1. Fix the store's base address to be a full absolute URL including scheme (http://host:9090)
  2. Validate the address at store-creation time with url.Parse before issuing queries
  3. Check config files/env vars feeding the address for empty or malformed values
  4. Verify path joining does not produce an invalid URL when the base path is unusual

Example fix

// before
address: "prometheus:9090"
// after
address: "http://prometheus:9090"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(addr)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid store address %q: need absolute URL with scheme", addr)
}

Try / catch

resp, err := store.Series(ctx, req)
if err != nil && strings.Contains(err.Error(), "unable to create request") {
    // address malformed: fix --store-address / config and re-create the store
}

Prevention

When it happens

Trigger: Constructing a PrometheusStore with --store-address / base URL that is empty, missing scheme (e.g. "prometheus:9090" instead of "http://prometheus:9090"), or contains characters http.NewRequest rejects (spaces, control chars).

Common situations: Typo in store address flag; missing http:// scheme prefix in static config or file_sd targets; environment interpolation producing an empty address; invalid characters from templated addresses.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/85fea78978a07d5f. Report an issue: GitHub.

Appendix: source

Thrown at pkg/store/prometheus.go:472

	return chks, nil
}

func (p *PrometheusStore) startPromRemoteRead(ctx context.Context, q *prompb.Query) (presp *http.Response, err error) {
	reqb, err := proto.Marshal(&prompb.ReadRequest{
		Queries:               []*prompb.Query{q},
		AcceptedResponseTypes: p.remoteReadAcceptableResponses,
	})
	if err != nil {
		return nil, errors.Wrap(err, "marshal read request")
	}

	u := *p.base
	u.Path = path.Join(u.Path, "api/v1/read")

	preq, err := http.NewRequest("POST", u.String(), bytes.NewReader(snappy.Encode(nil, reqb)))
	if err != nil {
		return nil, errors.Wrap(err, "unable to create request")
	}
	preq.Header.Add("Content-Encoding", "snappy")
	preq.Header.Set("Content-Type", "application/x-stream-protobuf")
	preq.Header.Set("X-Prometheus-Remote-Read-Version", "0.1.0")

	preq.Header.Set("User-Agent", clientconfig.ThanosUserAgent)
	presp, err = p.client.Do(preq.WithContext(ctx))
	if err != nil {
		return nil, errors.Wrap(err, "send request")
	}
	if presp.StatusCode/100 != 2 {
		// Best effort read.
		b, err := io.ReadAll(presp.Body)
		if err != nil {
			level.Error(p.logger).Log("msg", "failed to read response from non 2XX remote read request", "err", err)
		}
		_ = presp.Body.Close()
		return nil, errors.Errorf("request failed with code %s; msg %s", presp.Status, string(b))

View on GitHub (pinned to 35b8b99117)