thanos-io/thanos · error

unable to create new legacy file sd config

Error message

unable to create new legacy file sd config: %w

What it means

Raised when Thanos cannot instantiate the Prometheus common file-based service discovery (file.SDConfig) used for legacy endpoint files. The file discovery component watches legacy file_sd lists of store endpoints; construction failure (invalid config, metrics registry issues) aborts setupEndpointSet with this wrapped error.

Solutions

  1. Check the inner error from file.NewDiscovery; typically fix the legacy file SD flags (--store-file-sd) values (existing files list, valid refresh interval like 5m).
  2. Prefer the modern --endpoint-config / --endpoint-group-config mechanism over legacy file SD; migrate and remove legacy flags.
  3. Ensure the referenced file_sd files exist and contain a JSON list of targets; empty/nonexistent files are tolerated by watcher but check flags anyway.
  4. Upgrade/downgrade Thanos so prometheus/common discovery API matches; the error often indicates version skew.

Example fix

// before: legacy flags with bad interval
// --store-file-sd-refresh-interval=0s --store-file-sd=/etc/thanos/stores.json
// after
// --store-file-sd-refresh-interval=5m --store-file-sd=/etc/thanos/stores.json
// (or migrate) --endpoint-config=/etc/thanos/endpoints.yaml
Defensive patterns

Strategy: fallback

Validate before calling

for _, f := range legacyFileSDFiles { if _, err := os.Stat(f); err != nil { return fmt.Errorf("file_sd file missing: %s", f) } }

Type guard

func legacySDConfigured(files []string, interval model.Duration) bool { return len(files) > 0 && interval > 0 }

Try / catch

fileSD, err = file.NewDiscovery(conf, slogLogger, metrics)
if err != nil {
    logger.Warn("legacy file SD unavailable, continuing with static endpoints", "err", err)
    fileSD = nil
}

Prevention

When it happens

Trigger: file.NewDiscovery returns error after building SDConfig from --store-file-sd-* legacy flags (files list, refresh interval) and its discoverer metrics; e.g., nil registry, invalid RefreshInterval, or internal prometheus/common/discovery construction failure.

Common situations: Running legacy --store-file-sd flag paths with an incompatible prometheus/common version after an upgrade; refresh interval formatted incorrectly via model.Duration; registry/metrics registration collision.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at cmd/thanos/endpointset.go:366

				duplicatedEndpoints.Inc()
			}
			set[addr] = spec
		}
		deduplicated := make([]*query.GRPCEndpointSpec, 0, len(set))
		for _, value := range set {
			deduplicated = append(deduplicated, value)
		}
		return deduplicated
	}
	var fileSD *file.Discovery
	if len(legacyFileSDFiles) > 0 {
		conf := &file.SDConfig{
			Files:           legacyFileSDFiles,
			RefreshInterval: model.Duration(legacyFileSDInterval),
		}
		var err error
		if fileSD, err = file.NewDiscovery(conf, logutil.GoKitLogToSlog(logger), conf.NewDiscovererMetrics(reg, discovery.NewRefreshMetrics(reg))); err != nil {
			return nil, fmt.Errorf("unable to create new legacy file sd config: %w", err)
		}
	}
	legacyFileSDCache := cache.New()

	// Perform initial DNS resolution before starting periodic updates.
	// This ensures that DNS providers have addresses when the first endpoint update runs.
	{
		resolveCtx, resolveCancel := context.WithTimeout(context.Background(), dnsSDInterval)
		defer resolveCancel()

		level.Info(logger).Log("msg", "performing initial DNS resolution for endpoints")

		endpointConfig := configProvider.config()
		addresses := make([]string, 0, len(endpointConfig.Endpoints))
		for _, ecfg := range endpointConfig.Endpoints {
			// Only resolve non-group dynamic endpoints here.
			// Group endpoints are resolved by the gRPC resolver in its Build() method.
			if addr := ecfg.Address; dns.IsDynamicNode(addr) && !ecfg.Group {

View on GitHub (pinned to 35b8b99117)