GoogleContainerTools/skaffold · error

error creating REST client config in-cluster: %w

Error message

error creating REST client config in-cluster: %w

What it means

In getRestClientConfig, when no kubeContext and no kubeconfig path are given and the resulting client config is empty (clientcmd.IsEmptyConfig), Skaffold falls back to restclient.InClusterConfig(). If that fails — typically because the process is not running inside a Kubernetes pod — this wrapped error is returned.

Source

Thrown at pkg/skaffold/kubernetes/context/context.go:100

	}
	return c, nil
}

func getRestClientConfig(kctx string, kcfg string) (*restclient.Config, error) {
	log.Entry(context.TODO()).Debugf("getting client config for kubeContext: `%s`", kctx)

	rawConfig, err := getCurrentConfig()
	if err != nil {
		return nil, err
	}

	clientConfig := clientcmd.NewNonInteractiveClientConfig(rawConfig, kctx, &clientcmd.ConfigOverrides{CurrentContext: kctx}, clientcmd.NewDefaultClientConfigLoadingRules())
	restConfig, err := clientConfig.ClientConfig()
	if kctx == "" && kcfg == "" && clientcmd.IsEmptyConfig(err) {
		log.Entry(context.TODO()).Debug("no kube-context set and no kubeConfig found, attempting in-cluster config")
		restConfig, err := restclient.InClusterConfig()
		if err != nil {
			return restConfig, fmt.Errorf("error creating REST client config in-cluster: %w", err)
		}

		return restConfig, nil
	}
	if err != nil {
		return restConfig, fmt.Errorf("error creating REST client config for kubeContext %q: %w", kctx, err)
	}

	return restConfig, nil
}

// getCurrentConfig retrieves and caches the raw kubeConfig. The cache ensures that Skaffold always works with the identical kubeconfig,
// even if it was changed on disk.
func getCurrentConfig() (clientcmdapi.Config, error) {
	kubeConfigOnce.Do(func() {
		loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
		loadingRules.ExplicitPath = kubeConfigFile
		kubeConfig = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{

View on GitHub (pinned to a1189de023)

Solutions

  1. Provide a kubeconfig: set KUBECONFIG or run `kubectl config use-context <ctx>` so the in-cluster fallback isn't taken
  2. If in-cluster use is intended, run inside a pod with a mounted service-account token
  3. In-cluster, set automountServiceAccountToken: true on the pod spec

Example fix

// before: no kubeconfig, outside cluster -> InClusterConfig fails
// after
export KUBECONFIG=$HOME/.kube/config
kubectl config use-context minikube
Defensive patterns

Strategy: validation

Validate before calling

inCluster := os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != ""
hasKubeconfig := os.Getenv("KUBECONFIG") != ""
cfgExists, _ := fileExists(filepath.Join(homedir.HomeDir(), ".kube", "config"))
if !inCluster && !hasKubeconfig && !cfgExists {
    return errors.New("neither kubeconfig nor in-cluster credentials available")
}

Type guard

func hasConfigSource() bool {
    if os.Getenv("KUBECONFIG") != "" { return true }
    if _, err := os.Stat(filepath.Join(homedir.HomeDir(), ".kube", "config")); err == nil { return true }
    _, err := restclient.InClusterConfig()
    return err == nil
}

Try / catch

cfg, err := context.GetDefaultRestClientConfig()
if err != nil && strings.Contains(err.Error(), "in-cluster") {
    return fmt.Errorf("not running in a pod and no kubeconfig; set KUBECONFIG: %w", err)
}

Prevention

When it happens

Trigger: GetDefaultRestClientConfig (or GetRestClientConfig with empty kctx/kcfg) executed where: no KUBECONFIG file exists, and KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT env vars or /var/run/secrets/kubernetes.io/serviceaccount/token are absent (i.e., outside a pod).

Common situations: Running skaffold deploy on a laptop without any kubeconfig; CI container that is not an in-cluster pod; in-cluster pod with automountServiceAccountToken disabled.

Related errors


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