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
- Free the port: find and stop the process holding it (lsof -i :PORT or ss -ltnp), or remove a stale skaffold process.
- Run without --rpc-port so skaffold binds a random free port (it logs the chosen port).
- Choose a different, unprivileged port via --rpc-port (>=1024).
- 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
- Prefer letting skaffold pick a random port (omit --rpc-port) unless a client needs a fixed one
- Check for stale skaffold processes (ps aux | grep skaffold) before rerunning
- Use ports >= 1024 to avoid privilege issues
- Coordinate fixed RPC ports per developer/machine to avoid collisions
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
- starting HTTP server: %w
- INIT_DOCKER_NETWORK_CONTAINER_DOES_NOT_EXIST
- creating listener: %w
- getting latest and current skaffold versions: %w
- `apply` requires at least one manifest argument
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/aad9f6276d071143.
Report an issue: GitHub.