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
- Add a `stats.host` key with a host:port value (e.g. "127.0.0.1:2003") under the stats block
- Verify YAML indentation places stats.host inside stats alongside stats.type
- 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
- Always set stats.host whenever stats.type is graphite
- Validate the nebula config with a linter before SIGHUP reload
- Keep graphite and prometheus key sets separated per profile
- Check YAML indentation places stats.host inside the stats block
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
- stats.listen should not be empty
- stats.path should not be empty
- stats.interval was an invalid duration: %s
- error while setting up graphite sink: %s
- stats.type was not understood: %s
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/c5602a3d03ceaa2f.
Report an issue: GitHub.