thanos-io/thanos · error

parse limit configuration

Error message

parse limit configuration

What it means

After successfully reading the limits config content, runReceive parses the YAML into receive.RootLimitsConfig via receive.ParseRootLimitConfig. Any YAML syntax error or schema violation in the limit configuration is wrapped with 'parse limit configuration', aborting startup.

Solutions

  1. Validate the YAML with a linter (yamllint) or a quick yaml.Unmarshal test to find the syntax error at the reported line.
  2. Compare your config against the RootLimitsConfig schema / example config for your exact Thanos version.
  3. Check field names, types, and duration formats match the schema (e.g. tenantWriteLimits, headSeriesLimit).
  4. Ensure the file was not truncated or merged incorrectly by a templating system (Helm, ConfigMap).

Example fix

# before (bad: wrong type)
writeLimits:
  headSeriesLimit: "ten-thousand"
# after
writeLimits:
  headSeriesLimit: 10000
Defensive patterns

Strategy: validation

Validate before calling

var tmp receive.RootLimitsConfig
if err := yaml.UnmarshalStrict(content, &tmp); err != nil {
  return fmt.Errorf("invalid limits config %s: %w", limitsPath, err)
}

Try / catch

if err := run(); err != nil {
  if strings.Contains(err.Error(), "parse limit configuration") {
    log.Errorf("fix YAML/schema in limits config: %v", err)
  }
}

Prevention

When it happens

Trigger: --receive.limits-config points to a file whose content is invalid YAML or violates the RootLimitsConfig schema (wrong field names/types, e.g. a string where a duration or int is expected).

Common situations: Hand-edited limits.yaml with indentation mistakes; wrong keys copied from an older Thanos version's schema; durations written as '10s' where raw numbers are expected (or vice versa); tabs instead of spaces.

Related errors


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

Appendix: source

Thrown at cmd/thanos/receive.go:267

		bkt,
		conf.allowOutOfOrderUpload,
		conf.skipCorruptedBlocks,
		hashFunc,
		multiTSDBOptions...,
	)
	writer := receive.NewWriter(log.With(logger, "component", "receive-writer"), dbs, &receive.WriterOptions{
		TooFarInFutureTimeWindow: int64(time.Duration(*conf.tsdbTooFarInFutureTimeWindow)),
	})

	var limitsConfig *receive.RootLimitsConfig
	if conf.writeLimitsConfig != nil {
		limitsContentYaml, err := conf.writeLimitsConfig.Content()
		if err != nil {
			return errors.Wrap(err, "get content of limit configuration")
		}
		limitsConfig, err = receive.ParseRootLimitConfig(limitsContentYaml)
		if err != nil {
			return errors.Wrap(err, "parse limit configuration")
		}
	}
	limiter, err := receive.NewLimiter(conf.writeLimitsConfig, reg, receiveMode, log.With(logger, "component", "receive-limiter"), conf.limitsConfigReloadTimer)
	if err != nil {
		return errors.Wrap(err, "creating limiter")
	}

	webHandler := receive.NewHandler(log.With(logger, "component", "receive-handler"), &receive.Options{
		Writer:               writer,
		ListenAddress:        conf.rwAddress,
		Registry:             reg,
		Endpoint:             conf.endpoint,
		TenantHeader:         conf.tenantHeader,
		TenantField:          conf.tenantField,
		DefaultTenantID:      conf.defaultTenantID,
		ReplicaHeader:        conf.replicaHeader,
		ReplicationFactor:    conf.replicationFactor,
		RelabelConfigs:       relabelConfig,

View on GitHub (pinned to 35b8b99117)