apache/beam · error

failed to find open port for service, got

Error message

failed to find open port for service, got %v

What it means

NewExpansionServiceRunner launches a Java expansion service jar with exec.Command. When servicePort is empty, it requests a free port via findOpenPort(); if no port can be found it wraps that error as "failed to find open port for service". The runner is never created in that case.

Solutions

  1. Pass an explicit, known-free servicePort instead of "" so findOpenPort is skipped.
  2. Check system port availability (netstat/ss) and free up ephemeral ports or widen the ephemeral range (net.ipv4.ip_local_port_range).
  3. Verify localhost binding works (firewall, SELinux, container network policy).
  4. Retry later if the failure was transient port contention.

Example fix

// before
runner, err := expansionx.NewExpansionServiceRunner(jarPath, "")
// after
runner, err := expansionx.NewExpansionServiceRunner(jarPath, "55501") // known free port
Defensive patterns

Strategy: validation

Validate before calling

if servicePort == "" {
    l, err := net.Listen("tcp", "localhost:0")
    if err != nil {
        return fmt.Errorf("no bindable port available: %w", err)
    }
    servicePort = strconv.Itoa(l.Addr().(*net.TCPAddr).Port)
    l.Close()
}

Try / catch

runner, err := expansionx.NewExpansionServiceRunner(jar, port)
if err != nil {
    return fmt.Errorf("starting java expansion service on %s: %w", port, err)
}

Prevention

When it happens

Trigger: Calling NewExpansionServiceRunner with an empty servicePort string on a host where findOpenPort() cannot bind any listener (no available ports, network stack issues, listener creation error).

Common situations: Port exhaustion from many open sockets; restrictive firewall/SELinux blocking ephemeral port binding; running in sandboxes where binding to localhost is disallowed.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/6a2157a5d2ec010f. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/xlangx/expansionx/process.go:53

}

func findOpenPort() (int, error) {
	listener, err := net.Listen("tcp", ":0")
	if err != nil {
		return 0, err
	}
	defer listener.Close()
	return listener.Addr().(*net.TCPAddr).Port, nil
}

// NewExpansionServiceRunner builds an ExpansionServiceRunner struct for a given gradle target and
// Beam version and returns a pointer to it. Passing an empty string as servicePort will request an
// open port to be assigned to the service.
func NewExpansionServiceRunner(jarPath, servicePort string) (*ExpansionServiceRunner, error) {
	if servicePort == "" {
		port, err := findOpenPort()
		if err != nil {
			return nil, fmt.Errorf("failed to find open port for service, got %v", err)
		}
		servicePort = fmt.Sprintf("%d", port)
	}
	serviceCommand := exec.Command("java", "-jar", jarPath, servicePort)
	return &ExpansionServiceRunner{execPath: jarPath, servicePort: servicePort, serviceCommand: serviceCommand}, nil
}

// NewPyExpansionServiceRunner builds an ExpansionServiceRunner struct for a given python module and
// Beam version and returns a pointer to it. Passing an empty string as servicePort will request an
// open port to be assigned to the service.
func NewPyExpansionServiceRunner(pythonExec, module, servicePort string) (*ExpansionServiceRunner, error) {
	if servicePort == "" {
		port, err := findOpenPort()
		if err != nil {
			return nil, fmt.Errorf("failed to find open port for service, got %v", err)
		}
		servicePort = fmt.Sprintf("%d", port)
	}

View on GitHub (pinned to 12126d8942)