thanos-io/thanos · error

load tenant limits config

Error message

load tenant limits config

What it means

NewLimiter wraps any failure from limiter.loadConfig() — reading and parsing the tenant limits file or content — with the message 'load tenant limits config'. The root cause is in the wrapped error (file missing, unreadable, or invalid YAML/JSON), and the limiter fails to initialize.

Solutions

  1. Check the wrapped (%v) cause: if file-not-found, fix the --receive-limit-config path or mount the file
  2. Verify the file is readable by the process user (permissions, SELinux/container securityContext)
  3. Validate the config content parses (run ParseLimitConfigContent / a YAML linter) before startup
  4. If config is optional, pass nil/empty so NewLimiter skips loading (configFile == nil path)
  5. Set up StartConfigReloader only after NewLimiter succeeds; fix config before restart

Example fix

// before
limiter, err := NewLimiter(hashrings, backend, limitsConfigPath, ...)
// if limitsConfigPath is wrong: load tenant limits config: open /etc/thanos/limits.yml: no such file
// after
if _, err := os.Stat(limitsConfigPath); err != nil {
    log.Fatalf("limit config missing: %v", err)
}
limiter, err := NewLimiter(hashrings, backend, limitsConfigPath, ...)
Defensive patterns

Strategy: try-catch

Validate before calling

if limitCfgPath != "" {
    if _, err := os.Stat(limitCfgPath); err != nil {
        return nil, fmt.Errorf("limits config path invalid: %w", err)
    }
}

Try / catch

limiter, err := receive.NewLimiter(hashrings, bkt, cfgPath, limits, log)
if err != nil {
    return fmt.Errorf("starting receiver limiter: %w", err) // inspect wrapped cause
}

Prevention

When it happens

Trigger: Calling NewLimiter with a configFile path or content whose loadConfig() fails: the file does not exist, lacks read permission, or contains invalid limit config.

Common situations: Wrong path passed to the receiver's limit-config flag; file not mounted into the pod/container; config file not yet generated at startup; permissions changed after deployment.

Understand the failure class

Background: "Config file not found": what it means and how to fix it in docker-sync, Maven, Vagrant, Turborepo and other tools — this error's family across 60 libraries.

Related errors


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

Appendix: source

Thrown at pkg/receive/limiter.go:103

			},
		)
		limiter.configReloadFailedCounter = promauto.With(limiter.registerer).NewCounter(
			prometheus.CounterOpts{
				Namespace: "thanos",
				Subsystem: "receive",
				Name:      "limits_config_reload_err_total",
				Help:      "How many times the limit configuration failed to reload.",
			},
		)
	}

	if configFile == nil {
		return limiter, nil
	}

	limiter.configPathOrContent = configFile
	if err := limiter.loadConfig(); err != nil {
		return nil, errors.Wrap(err, "load tenant limits config")
	}

	return limiter, nil
}

// StartConfigReloader starts the automatic configuration reloader based off of
// the file indicated by pathOrContent. It starts a Go routine in the given
// *run.Group.
func (l *Limiter) StartConfigReloader(ctx context.Context) error {
	if !l.CanReload() {
		return nil
	}

	return extkingpin.PathContentReloader(ctx, l.configPathOrContent, l.logger, func() {
		level.Info(l.logger).Log("msg", "reloading limit config")
		if err := l.loadConfig(); err != nil {
			if failedReload := l.configReloadCounter; failedReload != nil {
				failedReload.Inc()

View on GitHub (pinned to 35b8b99117)