GoogleContainerTools/skaffold · error

starting gRPC server: %w

Error message

starting gRPC server: %w

What it means

server.Initialize wraps any failure from newGRPCServer — usually 'creating listener: ...' from failing to bind the preferred port — as 'starting gRPC server: %w'. Skaffold starts this gRPC API server when RPC is enabled (--rpc, --rpc-port, or --rpc-http-port) so IDEs/clients can query state and events.

Source

Thrown at pkg/skaffold/server/server.go:124

}

// Initialize creates the gRPC and HTTP servers for serving the state and event log.
// It returns a shutdown callback for tearing down the grpc server,
// which the runner is responsible for calling.
func Initialize(opts config.SkaffoldOptions) (func() error, error) {
	emptyCallback := func() error { return nil }
	if !opts.EnableRPC && opts.RPCPort.Value() == nil && opts.RPCHTTPPort.Value() == nil {
		log.Entry(context.TODO()).Debug("skaffold API not starting as it's not requested")
		return emptyCallback, nil
	}

	preferredGRPCPort := 0 // bind to an available port atomically
	if opts.RPCPort.Value() != nil {
		preferredGRPCPort = *opts.RPCPort.Value()
	}
	grpcCallback, grpcPort, err := newGRPCServer(preferredGRPCPort)
	if err != nil {
		return grpcCallback, fmt.Errorf("starting gRPC server: %w", err)
	}

	httpCallback := emptyCallback
	if opts.RPCHTTPPort.Value() != nil {
		httpCallback, err = newHTTPServer(*opts.RPCHTTPPort.Value(), grpcPort)
	}
	callback := func() error {
		// Optionally pause execution until endpoint hit
		if opts.WaitForConnection {
			eventV2.WaitForConnection()
		}

		httpErr := httpCallback()
		grpcErr := grpcCallback()
		errStr := ""
		if grpcErr != nil {
			errStr += fmt.Sprintf("grpc callback error: %s\n", grpcErr.Error())
		}

View on GitHub (pinned to a1189de023)

Solutions

  1. Free the port: find and stop the process holding it (lsof -i :PORT or ss -ltnp), or remove a stale skaffold process.
  2. Run without --rpc-port so skaffold binds a random free port (it logs the chosen port).
  3. Choose a different, unprivileged port via --rpc-port (>=1024).
  4. If a low port is required, grant the binary the capability or run with sufficient privileges.

Example fix

// before
skaffold dev --rpc-port 50051 // port already in use

// after
skaffold dev            # random port
# or
skaffold dev --rpc-port 50052
Defensive patterns

Strategy: retry

Validate before calling

// check the port is free before starting
if opts.RPCPort.Value() != nil {
	port := *opts.RPCPort.Value()
	if l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)); err != nil {
		return fmt.Errorf("port %d unavailable: %w", port, err)
	} else {
		l.Close()
	}
}

Try / catch

cb, err := server.Initialize(opts)
if err != nil && strings.Contains(err.Error(), "starting gRPC server") {
	// retry with a random port instead of the requested one
	opts.RPCPort = nil
	cb, err = server.Initialize(opts)
}
if err != nil {
	return err
}

Prevention

When it happens

Trigger: Calling Initialize(opts) with opts.EnableRPC or a non-nil RPCPort, and listenPort fails: the preferred port (--rpc-port N) is already in use by another process, the port is privileged (<1024 without permissions), or the network interface is unavailable.

Common situations: A stale Skaffold process still holds the configured --rpc-port; another dev tool (e.g. a debugger or another skaffold dev) is bound to the same port; running in a restricted container without the CAP_NET_BIND_SERVICE capability for low ports.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/aad9f6276d071143. Report an issue: GitHub.