slackhq/nebula · error

stats.host can not be empty

Error message

stats.host can not be empty

What it means

Nebula's loadStatsConfig validates the graphite stats sink configuration. When stats.type is "graphite", stats.host must be set to a resolvable host:port; if the host string is empty the config is rejected with this error and nebula refuses to (re)load the configuration.

Source

Thrown at stats.go:346

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 == "" {
			return cfg, errors.New("stats.listen should not be empty")
		}
		cfg.prom.path = c.GetString("stats.path", "")
		if cfg.prom.path == "" {
			return cfg, errors.New("stats.path should not be empty")
		}
		cfg.prom.namespace = c.GetString("stats.namespace", "")
		cfg.prom.subsystem = c.GetString("stats.subsystem", "")

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Add a `stats.host` key with a host:port value (e.g. "127.0.0.1:2003") under the stats block
  2. Verify YAML indentation places stats.host inside stats alongside stats.type
  3. If you intend prometheus instead, set stats.type: prometheus and configure stats.listen/stats.path

Example fix

# before
stats:
  type: graphite
  protocol: tcp
# after
stats:
  type: graphite
  protocol: tcp
  host: 127.0.0.1:2003
  prefix: nebula
Defensive patterns

Strategy: validation

Validate before calling

host := cfg.Stats["host"]
if cfg.Stats["type"] == "graphite" && (host == nil || host == "") {
    return errors.New("stats.host must be set when stats.type is graphite")
}

Try / catch

cfg, err := loadStatsConfig(raw)
if err != nil {
    if strings.Contains(err.Error(), "stats.host can not be empty") {
        return fmt.Errorf("stats config: set stats.host like 127.0.0.1:2003: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Setting `stats.type: graphite` in the nebula config without defining `stats.host` (or leaving it empty), during initial start or a config reload triggered via SIGHUP.

Common situations: Copy-pasting a stats config block and omitting stats.host; switching stats.type to graphite while only prometheus keys (stats.listen/stats.path) are present; malformed YAML indentation nesting stats.host outside the stats block.

Related errors


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