{"record":{"id":"b9cdc9c5b7c5c9f4","repo":"slackhq/nebula","slug":"stats-path-should-not-be-empty","errorCode":null,"errorMessage":"stats.path should not be empty","messagePattern":"stats\\.path should not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"stats.go","lineNumber":361,"sourceCode":"\t\tcfg.graphite.protocol = c.GetString(\"stats.protocol\", \"tcp\")\n\t\tcfg.graphite.host = c.GetString(\"stats.host\", \"\")\n\t\tif cfg.graphite.host == \"\" {\n\t\t\treturn cfg, errors.New(\"stats.host can not be empty\")\n\t\t}\n\t\taddr, err := net.ResolveTCPAddr(cfg.graphite.protocol, cfg.graphite.host)\n\t\tif err != nil {\n\t\t\treturn cfg, fmt.Errorf(\"error while setting up graphite sink: %s\", err)\n\t\t}\n\t\tcfg.graphite.resolvedAddr = addr.String()\n\t\tcfg.graphite.prefix = c.GetString(\"stats.prefix\", \"nebula\")\n\tcase \"prometheus\":\n\t\tcfg.prom.listen = c.GetString(\"stats.listen\", \"\")\n\t\tif cfg.prom.listen == \"\" {\n\t\t\treturn cfg, errors.New(\"stats.listen should not be empty\")\n\t\t}\n\t\tcfg.prom.path = c.GetString(\"stats.path\", \"\")\n\t\tif cfg.prom.path == \"\" {\n\t\t\treturn cfg, errors.New(\"stats.path should not be empty\")\n\t\t}\n\t\tcfg.prom.namespace = c.GetString(\"stats.namespace\", \"\")\n\t\tcfg.prom.subsystem = c.GetString(\"stats.subsystem\", \"\")\n\tdefault:\n\t\treturn cfg, fmt.Errorf(\"stats.type was not understood: %s\", cfg.typ)\n\t}\n\n\treturn cfg, nil\n}\n","sourceCodeStart":343,"sourceCodeEnd":371,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/stats.go#L343-L371","documentation":"For the prometheus stats sink, nebula requires stats.path — the URL path the metrics endpoint is served on — to be non-empty. loadStatsConfig returns this error when stats.listen is set but stats.path resolves to an empty string, aborting config load or reload.","triggerScenarios":"Configuring `stats.type: prometheus` with stats.listen but omitting or leaving stats.path empty during startup or SIGHUP reload.","commonSituations":"Minimal prometheus config examples that only show stats.listen; a stats.path key typo or wrong indentation; hand-written configs where the path was commented out.","solutions":["Add `stats.path: /metrics` (or your preferred path, starting with /) under the stats block","Confirm the key is inside the stats block at correct YAML indentation","If you only need graphite, switch stats.type to graphite and configure stats.host instead"],"exampleFix":"# before\nstats:\n  type: prometheus\n  listen: 127.0.0.1:8080\n# after\nstats:\n  type: prometheus\n  listen: 127.0.0.1:8080\n  path: /metrics","handlingStrategy":"validation","validationCode":"if cfg.Stats[\"type\"] == \"prometheus\" && (cfg.Stats[\"path\"] == nil || cfg.Stats[\"path\"] == \"\") {\n    return errors.New(\"stats.path must be set when stats.type is prometheus\")\n}","typeGuard":null,"tryCatchPattern":"cfg, err := loadStatsConfig(raw)\nif err != nil {\n    if strings.Contains(err.Error(), \"stats.path should not be empty\") {\n        return fmt.Errorf(\"prometheus stats needs stats.path, e.g. /metrics: %w\", err)\n    }\n    return err\n}","preventionTips":["Set stats.path: /metrics whenever stats.type is prometheus","Ensure the path starts with / and matches your scraper target","Validate the full prometheus triplet (listen, path, type) before reload","Avoid commented-out stats.path in shared config templates"],"tags":["nebula","config","prometheus","stats","validation"],"backgroundTag":"missing-config-key","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}