GoogleContainerTools/skaffold · error

unable to connect to Kubernetes: %w

Error message

unable to connect to Kubernetes: %w

What it means

Wraps the failure from kubernetes.FailIfClusterIsNotReachable during Deploy. Skaffold pre-checks cluster reachability before deploying so the user gets a clear 'unable to connect to Kubernetes' message instead of a confusing helm/kubectl error later in the deploy pipeline. The wrapped error carries the underlying cause (DNS, auth, context).

Source

Thrown at pkg/skaffold/deploy/helm/helm.go:251

	h.localImages = images
}

func (h *Deployer) TrackBuildArtifacts(builds, deployedImages []graph.Artifact) {
	deployutil.AddTagsToPodSelector(builds, deployedImages, h.podSelector)
	h.logger.RegisterArtifacts(builds)
}

// Deploy deploys the build results to the Kubernetes cluster
func (h *Deployer) Deploy(ctx context.Context, out io.Writer, builds []graph.Artifact, _ manifest.ManifestListByConfig) error {
	ctx, endTrace := instrumentation.StartTrace(ctx, "Deploy", map[string]string{
		"DeployerType": "helm",
	})
	defer endTrace()

	// Check that the cluster is reachable.
	// This gives a better error message when the cluster can't be reached.
	if err := kubernetes.FailIfClusterIsNotReachable(h.kubeContext); err != nil {
		return fmt.Errorf("unable to connect to Kubernetes: %w", err)
	}

	childCtx, endTrace := instrumentation.StartTrace(ctx, "Deploy_LoadImages")
	if err := h.imageLoader.LoadImages(childCtx, out, h.localImages, h.originalImages, builds); err != nil {
		endTrace(instrumentation.TraceEndError(err))
		return err
	}
	endTrace()

	olog.Entry(ctx).Infof("Deploying with helm v%s ...", h.helmVersion)

	dependencyGraph, err := NewDependencyGraph(h.Releases)
	if err != nil {
		return fmt.Errorf("unable to create dependency graph: %w", err)
	}

	levelByLevelReleases, err := dependencyGraph.GetReleasesByLevel()
	if err != nil {

View on GitHub (pinned to a1189de023)

Solutions

  1. Run `kubectl cluster-info --context <kubeContext>` to verify the cluster is reachable with the same kubeconfig
  2. Start or reconnect the cluster (minikube start, kind cluster create, connect VPN)
  3. Check the `kube-context` value in skaffold.yaml matches `kubectl config get-contexts`
  4. Refresh credentials (gcloud container clusters get-credentials / aws eks update-kubeconfig)

Example fix

// before
.deploy:
  script: skaffold run
// after
.deploy:
  script:
    - kubectl config use-context $KUBE_CONTEXT
    - kubectl cluster-info   # fail fast if unreachable
    - skaffold run
Defensive patterns

Strategy: try-catch

Validate before calling

import (
  "k8s.io/client-go/kubernetes"
  "k8s.io/client-go/tools/clientcmd"
)
func validateCluster(kubeContext string) error {
  cfg, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
    clientcmd.NewDefaultClientConfigLoadingRules(),
    &clientcmd.ConfigOverrides{CurrentContext: kubeContext}).ClientConfig()
  if err != nil { return err }
  _, err = kubernetes.NewForConfig(cfg).Discovery().ServerVersion()
  return err
}

Try / catch

err := deployer.Deploy(ctx, out)
var connErr error
if errors.As(err, &connErr) && strings.Contains(err.Error(), "unable to connect to Kubernetes") {
  // check kubeconfig, VPN, credentials, then retry once
}

Prevention

When it happens

Trigger: Calling Deployer.Deploy when the kubeconfig context points to an unreachable API server, credentials are expired/missing, or the kubeContext name does not exist.

Common situations: VPN not connected to a private cluster, KIND/minikube cluster stopped, GKE/EKS token expired, typo in kubectl context name, ~/.kube/config absent in CI containers.

Related errors


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