slackhq/nebula · error

stats.interval was an invalid duration: %s

Error message

stats.interval was an invalid duration: %s

What it means

loadStatsConfig reads stats.interval as a duration when a stats message type other than 'none' is enabled. If the value is missing, non-numeric, or <= 0 after parsing, the config load fails with this message echoing the raw string. Raised during reload/startup before any stats sink is created.

Source

Thrown at stats.go:338

		case <-t.C:
			for _, fn := range fns {
				fn()
			}
		}
	}
}

func loadStatsConfig(c *config.C) (statsConfig, error) {
	cfg := statsConfig{
		typ: c.GetString("stats.type", ""),
	}
	if cfg.typ == "" || cfg.typ == "none" {
		return cfg, nil
	}

	cfg.interval = c.GetDuration("stats.interval", 0)
	if cfg.interval <= 0 {
		return cfg, fmt.Errorf("stats.interval was an invalid duration: %s", c.GetString("stats.interval", ""))
	}

	switch cfg.typ {
	case "graphite":
		cfg.graphite.protocol = c.GetString("stats.protocol", "tcp")
		cfg.graphite.host = c.GetString("stats.host", "")
		if cfg.graphite.host == "" {
			return cfg, errors.New("stats.host can not be empty")
		}
		addr, err := net.ResolveTCPAddr(cfg.graphite.protocol, cfg.graphite.host)
		if err != nil {
			return cfg, fmt.Errorf("error while setting up graphite sink: %s", err)
		}
		cfg.graphite.resolvedAddr = addr.String()
		cfg.graphite.prefix = c.GetString("stats.prefix", "nebula")
	case "prometheus":
		cfg.prom.listen = c.GetString("stats.listen", "")
		if cfg.prom.listen == "" {

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Set stats.interval to a valid Go duration with units, e.g. 10s, 1m
  2. If you don't want metrics, set stats.type: none instead of removing interval
  3. Ensure the YAML key is under the stats: block and correctly indented
  4. Use unitless values with Go duration parsing rules only if intended — safest to always include s/m/h

Example fix

// before
stats:
  type: graphite
  interval: 10
// after
stats:
  type: graphite
  interval: 10s
Defensive patterns

Strategy: validation

Validate before calling

# Go: validate the duration the same way nebula does before deploying
if d, err := time.ParseDuration(cfg.Stats.Interval); err != nil || d <= 0 {
	log.Fatalf("stats.interval must be a positive Go duration like 10s, got %q", cfg.Stats.Interval)
}

Try / catch

try {
  loadConfig(path)
} catch (e) {
  if (e.message.includes("stats.interval was an invalid duration")) {
    console.error("set stats.interval with units, e.g. 10s; or use stats.type: none")
  }
  throw e
}

Prevention

When it happens

Trigger: stats.interval is absent, set to a non-duration string ('5', 'every minute', '1m0s typo'), a bare integer without a unit, or an explicit non-positive value while stats.type is graphite or prometheus.

Common situations: Writing interval: 10 instead of 10s in YAML; commenting out interval while keeping stats.type enabled; locale/typo issues like '30sec' instead of '30s'.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/abbae5d2e88fe745. Report an issue: GitHub.