{"record":{"id":"d1961b18c2a108dd","repo":"slackhq/nebula","slug":"invalid-sshd-listen-address-s","errorCode":null,"errorMessage":"invalid sshd.listen address: %s","messagePattern":"invalid sshd\\.listen address: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ssh.go","lineNumber":89,"sourceCode":"\t\t} else {\n\t\t\tssh.Stop()\n\t\t}\n\t})\n}\n\n// configSSH reads the ssh info out of the passed-in Config and\n// updates the passed-in SSHServer. On success, it returns a function\n// that callers may invoke to run the configured ssh server. On\n// failure, it returns nil, error.\nfunc configSSH(l *slog.Logger, ssh *sshd.SSHServer, c *config.C) (func(), error) {\n\tlisten := c.GetString(\"sshd.listen\", \"\")\n\tif listen == \"\" {\n\t\treturn nil, fmt.Errorf(\"sshd.listen must be provided\")\n\t}\n\n\t_, port, err := net.SplitHostPort(listen)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid sshd.listen address: %s\", err)\n\t}\n\tif port == \"22\" {\n\t\treturn nil, fmt.Errorf(\"sshd.listen can not use port 22\")\n\t}\n\n\thostKeyPathOrKey := c.GetString(\"sshd.host_key\", \"\")\n\tif hostKeyPathOrKey == \"\" {\n\t\treturn nil, fmt.Errorf(\"sshd.host_key must be provided\")\n\t}\n\n\tvar hostKeyBytes []byte\n\tif strings.Contains(hostKeyPathOrKey, \"-----BEGIN\") {\n\t\thostKeyBytes = []byte(hostKeyPathOrKey)\n\t} else {\n\t\thostKeyBytes, err = os.ReadFile(hostKeyPathOrKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error while loading sshd.host_key file: %s\", err)\n\t\t}","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/ssh.go#L71-L107","documentation":"configSSH parses sshd.listen with net.SplitHostPort to extract the port. If the value is not a well-formed host:port address, SplitHostPort fails and the error is wrapped as \"invalid sshd.listen address\". This guards against malformed listen strings before any socket is opened.","triggerScenarios":"Setting sshd.listen to something without a port (\"0.0.0.0\"), with too many colons (\"host:1:2\" unbracketed), or a bare port number (\"2222\"), so net.SplitHostPort returns an error in ssh.go's configSSH.","commonSituations":"IPv6 addresses written unbracketed (\"::1:2222\"); missing the port entirely; copying a systemd-style listen directive that SplitHostPort cannot parse; stray whitespace or quotes inside the value.","solutions":["Use a host:port form such as \"0.0.0.0:2222\"; bracket IPv6 hosts: \"[::1]:2222\".","Test the value with net.SplitHostPort locally before deploying.","Trim whitespace and remove surrounding quotes from the config value."],"exampleFix":"// before\nsshd.listen = \"0.0.0.0\"\n// after\nsshd.listen = \"0.0.0.0:2222\"","handlingStrategy":"validation","validationCode":"raw := cfg.GetString(\"sshd.listen\", \"\")\nif _, _, err := net.SplitHostPort(raw); err != nil {\n    return fmt.Errorf(\"sshd.listen %q must be host:port (bracket IPv6: [::1]:2222)\", raw)\n}","typeGuard":null,"tryCatchPattern":"run, err := configSSH(logger, srv, c)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid sshd.listen address\") {\n        logger.Error(\"bad sshd.listen, want host:port\", \"value\", c.GetString(\"sshd.listen\", \"\"))\n        os.Exit(78)\n    }\n    return err\n}","preventionTips":["Always write IPv6 listen addresses with brackets: [::1]:2222.","Trim whitespace and quotes from config values before validation.","Unit-test your config loader against the exact sshd.listen strings you deploy."],"tags":["ssh","configuration","address-parsing"],"backgroundTag":"invalid-listen-address","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"}