thanos-io/thanos · error

downstream URL should be configured

Error message

downstream URL should be configured

What it means

The query-frontend acts as a proxy and forwards requests to a downstream Prometheus-compatible URL; Validate() requires cfg.DownstreamURL to be non-empty. Without it the frontend has nowhere to send uncached/split queries, so startup is aborted.

Solutions

  1. Set downstream_url in the query_frontend config block to the upstream Prometheus/Thanos query URL
  2. When using env expansion, ensure the environment variable is defined in the pod/container
  3. Verify the flag -query-frontend.downstream-url is passed if configuring via flags
  4. Point it at the correct scheme and address, e.g. http://thanos-query:9090

Example fix

// before
query_frontend:
  split_queries_by_interval: 15m
// after
query_frontend:
  downstream_url: http://thanos-query:9090
  split_queries_by_interval: 15m
Defensive patterns

Strategy: validation

Validate before calling

if cfg.DownstreamURL == "" {
    return errors.New("query_frontend.downstream_url must be set")
}
if _, err := url.Parse(cfg.DownstreamURL); err != nil {
    return fmt.Errorf("downstream_url malformed: %w", err)
}

Type guard

func downstreamConfigured(cfg Config) bool { return cfg.DownstreamURL != "" }

Try / catch

if err := cfg.Validate(); err != nil {
    if strings.Contains(err.Error(), "downstream URL") {
        log.Fatalf("configure -query-frontend.downstream-url: %v", err)
    }
}

Prevention

When it happens

Trigger: Config.Validate is called with cfg.DownstreamURL == "" — the downstream_url (or -query-frontend.downstream-url flag) was not set, or was set to an empty string via env expansion.

Common situations: Minimal query-frontend deployments where operators enabled split/cache features but forgot the downstream target; environment-variable-based configs where DOWNSTREAM_URL is unset in the deployment environment; typos leaving the key under the wrong YAML block.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at pkg/queryfrontend/config.go:301

			return err
		}
	}

	if cfg.LabelsConfig.ResultsCacheConfig != nil {
		if cfg.LabelsConfig.SplitQueriesByInterval <= 0 {
			return errors.New("split queries interval should be greater than 0  when caching is enabled")
		}
		if err := cfg.LabelsConfig.ResultsCacheConfig.Validate(querier.Config{}); err != nil {
			return errors.Wrap(err, "invalid ResultsCache config for labels tripperware")
		}
	}

	if cfg.DefaultTimeRange == 0 {
		return errors.New("labels.default-time-range cannot be set to 0")
	}

	if cfg.DownstreamURL == "" {
		return errors.New("downstream URL should be configured")
	}

	return nil
}

func (cfg *Config) validateDynamicSplitParams() error {
	if cfg.HorizontalShards <= 0 {
		return errors.New("min horizontal shards should be greater than 0 when query split threshold is enabled")
	}

	if cfg.MaxQuerySplitInterval <= 0 {
		return errors.New("max query split interval should be greater than 0 when query split threshold is enabled")
	}

	if cfg.MinQuerySplitInterval <= 0 {
		return errors.New("min query split interval should be greater than 0 when query split threshold is enabled")
	}
	return nil

View on GitHub (pinned to 35b8b99117)