{"record":{"id":"2dbc85728e8e989d","repo":"cloudflare/cloudflared","slug":"failed-to-listen-to-default-metrics-address-w","errorCode":null,"errorMessage":"failed to listen to default metrics address: %w","messagePattern":"failed to listen to default metrics address: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"metrics/metrics.go","lineNumber":128,"sourceCode":"//\n// In case the provided address is not the default one then it will be used\n// as is.\nfunc CreateMetricsListener(listeners *gracenet.Net, laddr string) (net.Listener, error) {\n\tif laddr == GetMetricsDefaultAddress(Runtime) {\n\t\t// On the presence of the default address select\n\t\t// a port from the known set of addresses iteratively.\n\t\taddresses := GetMetricsKnownAddresses(Runtime)\n\t\tfor _, address := range addresses {\n\t\t\tlistener, err := listeners.Listen(\"tcp\", address)\n\t\t\tif err == nil {\n\t\t\t\treturn listener, nil\n\t\t\t}\n\t\t}\n\n\t\t// When no port is available then bind to a random one\n\t\tlistener, err := listeners.Listen(\"tcp\", laddr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to listen to default metrics address: %w\", err)\n\t\t}\n\n\t\treturn listener, nil\n\t}\n\n\t// Explicitly got a local address then bind to it\n\tlistener, err := listeners.Listen(\"tcp\", laddr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to bind to address (%s): %w\", laddr, err)\n\t}\n\n\treturn listener, nil\n}\n\nfunc ServeMetrics(\n\tl net.Listener,\n\tctx context.Context,\n\tconfig Config,","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/metrics/metrics.go#L110-L146","documentation":"This error is returned by metrics server listener creation in cloudflared when binding to the *default* metrics address fails. Before falling back, cloudflared probes a default address (e.g. localhost:20241 or the configured metrics port); if listeners.Listen on that default address fails, the underlying net error is wrapped with this message. It almost always means the default port is already in use or the address is unbindable.","triggerScenarios":"Starting cloudflared with metrics enabled (metricsServeClient / UpdateConfiguration / RegisterConnection etc. trigger listener creation) while the default metrics port is already occupied by another process or a previous cloudflared instance, or when the default address cannot be resolved/bound (e.g. IPv6-only loopback issues, privileged port).","commonSituations":"Running multiple cloudflared instances on one host without changing --metrics; a stale cloudflared process holding the metrics port; containers/Podman restricting loopback binds; setting metrics to a port below 1024 without privileges.","solutions":["Check what holds the default metrics port (lsof -i :20241 / ss -ltnp) and stop the conflicting process","Start cloudflared with an explicit free --metrics 127.0.0.1:<port> so the default-address path is skipped","If no port is intended to be shared, note the code falls back to a random port only when the address probe fails intentionally — verify firewall/SELinux is not blocking the bind","On constrained environments, ensure localhost resolution works (correct /etc/hosts) so the default address can be bound"],"exampleFix":"// before\ncloudflared tunnel run --metrics localhost:20241\n// after\ncloudflared tunnel run --metrics localhost:20341  # free port chosen after checking ss -ltnp","handlingStrategy":"validation","validationCode":"const defaultMetricsAddr = \"localhost:20241\"\nconn, err := net.DialTimeout(\"tcp\", defaultMetricsAddr, time.Second)\nif err == nil {\n    conn.Close()\n    // port busy — configure --metrics to a free port before starting cloudflared\n}\nif ln, err := net.Listen(\"tcp\", \"127.0.0.1:0\"); err != nil {\n    // no bindable port at all — fix host networking/firewall\n} else {\n    ln.Close()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set an explicit --metrics address per instance in multi-instance hosts","Check for stale cloudflared processes before restart (pidfiles, ss -ltnp)","In containers, confirm loopback binds are permitted and the port is not claimed by a sidecar"],"tags":["go","network","metrics","port-conflict"],"backgroundTag":"address-already-in-use","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}