{"record":{"id":"ac9a7e42b00c3d6e","repo":"benbjohnson/litestream","slug":"must-specify-port-for-bind-address-q","errorCode":null,"errorMessage":"must specify port for bind address: %q","messagePattern":"must specify port for bind address: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/litestream/replicate.go","lineNumber":355,"sourceCode":"\t\t\tslogWith.Info(\"replicating to\", \"bucket\", client.Bucket, \"path\", client.Path)\n\t\tcase *abs.ReplicaClient:\n\t\t\tslogWith.Info(\"replicating to\", \"bucket\", client.Bucket, \"path\", client.Path, \"endpoint\", client.Endpoint)\n\t\tcase *sftp.ReplicaClient:\n\t\t\tslogWith.Info(\"replicating to\", \"host\", client.Host, \"user\", client.User, \"path\", client.Path)\n\t\tcase *nats.ReplicaClient:\n\t\t\tslogWith.Info(\"replicating to\", \"bucket\", client.BucketName, \"url\", client.URL)\n\t\tcase *oss.ReplicaClient:\n\t\t\tslogWith.Info(\"replicating to\", \"bucket\", client.Bucket, \"path\", client.Path, \"region\", client.Region)\n\t\tdefault:\n\t\t\tslogWith.Info(\"replicating to\")\n\t\t}\n\t}\n\n\t// Serve metrics over HTTP if enabled.\n\tif c.Config.Addr != \"\" {\n\t\thostport := c.Config.Addr\n\t\tif host, port, _ := net.SplitHostPort(c.Config.Addr); port == \"\" {\n\t\t\treturn fmt.Errorf(\"must specify port for bind address: %q\", c.Config.Addr)\n\t\t} else if host == \"\" {\n\t\t\thostport = net.JoinHostPort(\"localhost\", port)\n\t\t}\n\n\t\tslog.Info(\"serving metrics on\", \"url\", fmt.Sprintf(\"http://%s/metrics\", hostport))\n\t\tgo func() {\n\t\t\thttp.Handle(\"/metrics\", promhttp.Handler())\n\t\t\tif err := http.ListenAndServe(c.Config.Addr, nil); err != nil {\n\t\t\t\tslog.Error(\"cannot start metrics server\", \"error\", err)\n\t\t\t}\n\t\t}()\n\t}\n\n\t// Parse exec commands args & start subprocess.\n\tif c.Config.Exec != \"\" {\n\t\texecArgs, err := shellwords.Parse(c.Config.Exec)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse exec command: %w\", err)","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/cmd/litestream/replicate.go#L337-L373","documentation":"When the `addr` config option is set, Litestream serves Prometheus metrics over HTTP. The address must include a port; `net.SplitHostPort` returning an empty port means only a host was given. Run rejects it since there is no meaningful default metrics port.","triggerScenarios":"Config sets `addr: localhost` or `addr: 0.0.0.0` (no `:port` suffix), so `port == \"\"` in Run's metrics-server setup at replicate.go:355.","commonSituations":"Users copying `addr:` host-only examples, assuming a default port exists, or editing config and dropping the `:9090` suffix.","solutions":["Append a port to the address in the config, e.g. `addr: localhost:9090`","Use `addr: :9090` to bind all interfaces on a port","Remove the `addr` option entirely if metrics serving is not needed"],"exampleFix":"// before (litestream.yml)\naddr: localhost\n// after\naddr: localhost:9090","handlingStrategy":"validation","validationCode":"# validate addr includes a port\nADDR=$(yq '.addr' litestream.yml)\nif [ -n \"$ADDR\" ] && [[ \"$ADDR\" != *:* ]]; then\n  echo \"addr must include a port, e.g. $ADDR:9090\" >&2; exit 1\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write addr as host:port or :port","Add a config linter/CI check for the addr field","Document the metrics port in deployment templates"],"tags":["config","http","metrics"],"backgroundTag":"invalid-config-value","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}