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
- 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).
- Prefer the modern --endpoint-config / --endpoint-group-config mechanism over legacy file SD; migrate and remove legacy flags.
- 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.
- 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
- Migrate off legacy --store-file-sd flags to --endpoint-config.
- Verify prometheus/common version matches your Thanos build after upgrades.
- Use valid model.Duration values for refresh interval.
- Ensure referenced file_sd files exist and are valid JSON lists.
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
- unable to load config content
- unable to unmarshal config content
- endpoint
- unable to load config file
- unable to validate endpoints
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)