cloudflare/cloudflared · error

failed to start forwarding server

Error message

failed to start forwarding server

What it means

StartForwarder wraps any error from net.Listen when trying to bind the local TCP forwarding address. It means cloudflared could not set up the local listener that proxies connections to the origin over the tunnel. The wrapped underlying error (e.g. 'address already in use' or 'permission denied') is the actual cause.

Source

Thrown at carrier/carrier.go:70

// Write will write to Stdout
func (c *StdinoutStream) Write(p []byte) (int, error) {
	return os.Stdout.Write(p)
}

// Helper to allow deferring the response close with a check that the resp is not nil
func closeRespBody(resp *http.Response) {
	if resp != nil {
		_ = resp.Body.Close()
	}
}

// StartForwarder will setup a listener on a specified address/port and then
// forward connections to the origin by calling `Serve()`.
func StartForwarder(conn Connection, address string, shutdownC <-chan struct{}, options *StartOptions) error {
	listener, err := net.Listen("tcp", address)
	if err != nil {
		return errors.Wrap(err, "failed to start forwarding server")
	}
	return Serve(conn, listener, shutdownC, options)
}

// StartClient will copy the data from stdin/stdout over a WebSocket connection
// to the edge (originURL)
func StartClient(conn Connection, stream io.ReadWriter, options *StartOptions) error {
	return conn.ServeStream(options, stream)
}

// Serve accepts incoming connections on the specified net.Listener.
// Each connection is handled in a new goroutine: its data is copied over a
// WebSocket connection to the edge (originURL).
// `Serve` always closes `listener`.
func Serve(remoteConn Connection, listener net.Listener, shutdownC <-chan struct{}, options *StartOptions) error {
	defer listener.Close()
	errChan := make(chan error)

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Check if another process is bound to the address/port (lsof -i :<port> or netstat) and stop it or pick a different port.
  2. If using a privileged port, run as root, grant CAP_NET_BIND_SERVICE, or use a port >= 1024.
  3. Verify the --url address format (host:port) and that the interface/IP exists on the machine.
  4. Ensure only one cloudflared instance (or forwarding server) uses this address at a time.

Example fix

// before
StartForwarder(conn, "localhost:80", shutdownC, options)
// after
StartForwarder(conn, "localhost:8080", shutdownC, options)
Defensive patterns

Strategy: validation

Validate before calling

ln, err := net.Listen("tcp", address)
if err != nil {
	return fmt.Errorf("address %s unavailable: %w", address, err)
}
ln.Close() // free it before handing to StartForwarder

Try / catch

if err := carrier.StartForwarder(conn, addr, shutdownC, opts); err != nil {
	var oe *net.OpError
	if errors.As(err, &oe) && strings.Contains(oe.Error(), "address already in use") {
		addr = "localhost:0" // retry with ephemeral port
	}
}

Prevention

When it happens

Trigger: Calling StartForwarder with an address that is already bound, a privileged port (<1024) without root/CAP_NET_BIND_SERVICE, an invalid address string, or an address on an interface that does not exist.

Common situations: Running two cloudflared instances at once (the second fails to bind --url), firing up a second copy of a dev server on the same local port, using port 80/443 as non-root, or a misconfigured --url value with a typo in the host/IP.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/18fc65e67a60aecc. Report an issue: GitHub.