cloudflare/cloudflared · error
failed to listen to default metrics address: %w
Error message
failed to listen to default metrics address: %w
What it means
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.
Source
Thrown at metrics/metrics.go:128
//
// In case the provided address is not the default one then it will be used
// as is.
func CreateMetricsListener(listeners *gracenet.Net, laddr string) (net.Listener, error) {
if laddr == GetMetricsDefaultAddress(Runtime) {
// On the presence of the default address select
// a port from the known set of addresses iteratively.
addresses := GetMetricsKnownAddresses(Runtime)
for _, address := range addresses {
listener, err := listeners.Listen("tcp", address)
if err == nil {
return listener, nil
}
}
// When no port is available then bind to a random one
listener, err := listeners.Listen("tcp", laddr)
if err != nil {
return nil, fmt.Errorf("failed to listen to default metrics address: %w", err)
}
return listener, nil
}
// Explicitly got a local address then bind to it
listener, err := listeners.Listen("tcp", laddr)
if err != nil {
return nil, fmt.Errorf("failed to bind to address (%s): %w", laddr, err)
}
return listener, nil
}
func ServeMetrics(
l net.Listener,
ctx context.Context,
config Config,View on GitHub (pinned to 2253eeeb25)
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
Example fix
// before cloudflared tunnel run --metrics localhost:20241 // after cloudflared tunnel run --metrics localhost:20341 # free port chosen after checking ss -ltnp
Defensive patterns
Strategy: validation
Validate before calling
const defaultMetricsAddr = "localhost:20241"
conn, err := net.DialTimeout("tcp", defaultMetricsAddr, time.Second)
if err == nil {
conn.Close()
// port busy — configure --metrics to a free port before starting cloudflared
}
if ln, err := net.Listen("tcp", "127.0.0.1:0"); err != nil {
// no bindable port at all — fix host networking/firewall
} else {
ln.Close()
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- failed to bind to address (%s): %w
- failed to start forwarding server
- Error opening metrics server listener
- failed to build quick tunnel request
- failed to request quick Tunnel
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/2dbc85728e8e989d.
Report an issue: GitHub.