dapr/dapr · error

failed to start API gRPC server: %w

Error message

failed to start API gRPC server: %w

What it means

Returned when DaprRuntime.Run cannot start the public API gRPC server (startGRPCAPIServer). The underlying failure is almost always the net.Listen on the API gRPC port (default 50001) or, when --unix-domain-socket is set, creating the gRPC Unix domain socket file. The error wraps the OS-level cause; startup aborts.

Source

Thrown at pkg/runtime/runtime.go:821

	if err = a.loadWorkflowAccessPolicies(ctx); err != nil {
		return fmt.Errorf("failed to load workflow access policies: %w", err)
	}

	a.reloader.SetPolicyRecompiler(reconciler.WorkflowAccessPolicyOptions{
		AppID:      a.runtimeConfig.id,
		Loader:     a.reloader.Loader(),
		CompStore:  a.compStore,
		Recompiler: a.workflowAccessPolicies.Store,
		Healthz:    a.runtimeConfig.healthz,
	})

	if err = a.runnerCloser.AddCloser(a.daprGRPCAPI); err != nil {
		return err
	}

	err = a.startGRPCAPIServer(ctx, a.daprGRPCAPI, a.runtimeConfig.apiGRPCPort)
	if err != nil {
		return fmt.Errorf("failed to start API gRPC server: %w", err)
	}

	if a.runtimeConfig.unixDomainSocket != "" {
		log.Info("API gRPC server is running on a Unix Domain Socket")
	} else {
		log.Infof("API gRPC server is running on port %v", a.runtimeConfig.apiGRPCPort)
	}

	// Start HTTP Server
	err = a.startHTTPServer(ctx)
	if err != nil {
		return fmt.Errorf("failed to start HTTP server: %w", err)
	}

	if a.runtimeConfig.unixDomainSocket != "" {
		log.Info("HTTP server is running on a Unix Domain Socket")
	} else {
		log.Infof("HTTP server is running on port %v", a.runtimeConfig.httpPort)

View on GitHub (pinned to 74ad417027)

Solutions

  1. Inspect the wrapped error: 'address already in use' means a port conflict, 'permission denied' means privileged port or UDS dir perms
  2. Free the conflicting port (lsof -i :50001) or set a different one via --dapr-grpc-port
  3. If using --unix-domain-socket, ensure the directory exists, is writable by the daprd user, and is on a filesystem that supports UDS (not NFS/overlay quirks)
  4. Ensure only one daprd runs per app-id/port pair

Example fix

# before
daprd --app-id myapp --dapr-grpc-port 50001
# after (port 50001 taken by another process)
daprd --app-id myapp --dapr-grpc-port 50101
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: is the API gRPC port bindable?
func checkPortFree(port int) error {
    ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
    if err != nil { return fmt.Errorf("gRPC API port %d unavailable: %w", port, err) }
    ln.Close()
    return nil
}

Type guard

func isAddrInUse(err error) bool {
    var opErr *net.OpError
    if errors.As(err, &opErr) {
        return errors.Is(opErr.Err, syscall.EADDRINUSE)
    }
    return false
}

Prevention

When it happens

Trigger: Another process already bound the API gRPC port; --dapr-grpc-port set to a privileged port (<1024) while running unprivileged; Unix domain socket directory missing, read-only, or lacking write permission; port already taken by a second daprd instance for the same app-id.

Common situations: Two sidecars (or a leftover daprd) on the same host using default port 50001; container with a read-only volume mounted as the UDS dir; SELinux/AppArmor denying socket creation; Docker port-map collision.

Related errors


AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16). Data as JSON: /api/errors/b705591b95dc9eab. Report an issue: GitHub.