dapr/dapr · critical
unable to get controller runtime configuration, err: %s
Error message
unable to get controller runtime configuration, err: %s
What it means
NewOperator calls controller-runtime's ctrl.GetConfig() to resolve a Kubernetes *rest.Config. GetConfig tries in-cluster config first (KUBERNETES_SERVICE_HOST/PORT env vars plus the mounted service-account token), then falls back to $KUBECONFIG or ~/.kube/config. The error means none of these sources produced a usable config: not running in a pod, no kubeconfig file, or a malformed/unreadable one, so the Dapr Operator cannot build any Kubernetes client and aborts startup.
Source
Thrown at pkg/operator/operator.go:111
type operator struct {
apiServer api.Server
config *Config
mgr ctrl.Manager
podMetaCache ctrlcache.Cache
secProvider security.Provider
secHealthz healthz.Target
apiServerHealthz healthz.Target
webhookHealthz healthz.Target
cacheHealthz healthz.Target
}
// NewOperator returns a new Dapr Operator.
func NewOperator(ctx context.Context, opts Options) (Operator, error) {
conf, err := ctrl.GetConfig()
if err != nil {
return nil, fmt.Errorf("unable to get controller runtime configuration, err: %s", err)
}
config, err := LoadConfiguration(ctx, opts.Config, conf)
if err != nil {
return nil, fmt.Errorf("unable to load configuration, config: %s, err: %w", opts.Config, err)
}
secProvider, err := security.New(ctx, security.Options{
SentryAddress: config.SentryAddress,
ControlPlaneTrustDomain: config.ControlPlaneTrustDomain,
ControlPlaneNamespace: security.CurrentNamespace(),
TrustAnchorsFile: &opts.TrustAnchorsFile,
AppID: "dapr-operator",
// mTLS is always enabled for the operator.
MTLSEnabled: true,
Mode: modes.KubernetesMode,
Healthz: opts.Healthz,
// The operator serves CRD conversion / validating / mutating webhooksView on GitHub (pinned to 74ad417027)
Solutions
- Outside Kubernetes: export KUBECONFIG=/path/to/kubeconfig (or place it at ~/.kube/config) pointing at the target cluster.
- In a pod: verify the pod has a service account and the env vars exist (kubectl exec deploy/dapr-operator -- env | grep KUBERNETES).
- Validate the kubeconfig itself: kubectl cluster-info --kubeconfig $KUBECONFIG.
- Check readability of /var/run/secrets/kubernetes.io/serviceaccount/token and of the kubeconfig file (permissions, mount path).
Example fix
# before ./operator --config daprsystem # fails: no kubeconfig anywhere # after export KUBECONFIG=~/clusters/dev.yaml ./operator --config daprsystem
Defensive patterns
Strategy: validation
Validate before calling
import (
"fmt"
"os"
"path/filepath"
)
// PrecheckKubeConfig reports whether ctrl.GetConfig() will find a usable source.
func PrecheckKubeConfig() error {
if os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "" {
return nil // in-cluster config available
}
for _, p := range filepath.SplitList(os.Getenv("KUBECONFIG")) {
if p == "" {
continue
}
if _, err := os.Stat(p); err == nil {
return nil
}
}
home, _ := os.UserHomeDir()
if _, err := os.Stat(filepath.Join(home, ".kube", "config")); err == nil {
return nil
}
return fmt.Errorf("no kubeconfig source: set KUBECONFIG or run in-cluster")
} Try / catch
op, err := operator.NewOperator(ctx, opts)
if err != nil {
if strings.Contains(err.Error(), "unable to get controller runtime configuration") {
// config-source problem: fix env/kubeconfig, not the cluster
log.Fatalf("missing kube config: set KUBECONFIG or run inside a cluster: %v", err)
}
log.Fatalf("operator startup failed: %v", err)
} Prevention
- Always export KUBECONFIG explicitly in scripts/CI that run control-plane binaries outside a cluster.
- For local operator runs, target a kind/minikube kubeconfig and never rely on ambient defaults.
- In-cluster, keep the service-account token mount and KUBERNETES_* env vars intact in the pod spec.
When it happens
Trigger: Running the dapr-operator binary outside a pod with KUBECONFIG unset and no ~/.kube/config; $KUBECONFIG pointing at a deleted or invalid YAML file; a pod whose service-account token volume or KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT env vars were stripped (e.g., by a mutated pod spec or bare pod template).
Common situations: Local debugging of the operator against kind/minikube without exporting a kubeconfig; CI pipelines that execute the binary with no cluster credentials; hardened base images that omit the service-account mount.
Related errors
- unable to load configuration, config: %s, err: %w
- kubeconfig flag is only valid in --mode=kubernetes
- timeout waiting for api server to be ready
- cache failed to sync
- configuration %s not found
AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16).
Data as JSON: /api/errors/732f4934a575f2b3.
Report an issue: GitHub.