derailed/k9s · error

unable to launch shell pod on node %s

Error message

unable to launch shell pod on node %s

What it means

Node-shell flow: k9s creates a privileged helper pod (k9s-<pid>) on the target node and polls its Status.Phase in a retry loop with k9sShellRetryDelay until Running or ctx.Done(). This error means the pod never reached Running within the wait window — the pod is Pending/ImagePullBackOff/CrashLoopOff, or the context/timeout expired first.

Source

Thrown at internal/view/exec.go:467

		if err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &pod); err != nil {
			return err
		}
		slog.Debug("Checking k9s shell pod retries",
			slogs.Retry, i,
			slogs.PodPhase, pod.Status.Phase,
		)
		if pod.Status.Phase == v1.PodRunning {
			return nil
		}

		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-time.After(k9sShellRetryDelay):
		}
	}

	return fmt.Errorf("unable to launch shell pod on node %s", node)
}

func k9sShellPodName() string {
	return fmt.Sprintf("%s-%d", k9sShell, os.Getpid())
}

func k9sShellPod(node string, cfg *config.ShellPod) *v1.Pod {
	var grace int64
	var priv = true

	slog.Debug("Shell pod config", slogs.ShellPodCfg, cfg)
	c := v1.Container{
		Name:            k9sShell,
		Image:           cfg.Image,
		ImagePullPolicy: cfg.ImagePullPolicy,
		VolumeMounts: []v1.VolumeMount{
			{
				Name:      "root-vol",

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Check the helper pod directly: kubectl get pod k9s-<pid> -n kube-system and kubectl describe it — events show ImagePullBackOff, Unschedulable, or admission denial
  2. Set an image reachable from the cluster in k9s config: shellPod.image (e.g. an internal registry mirror)
  3. Verify the node is schedulable (kubectl uncordon <node>) and has capacity
  4. Grant the user pod-create permissions in kube-system if RBAC is the blocker

Example fix

# before (k9s config.yaml — default image unreachable in air-gapped cluster)
k9s:
  shellPod: {}
# after — point at an in-cluster reachable image
k9s:
  shellPod:
    image: registry.internal/mirror/alpine:3.20
    command: ["/bin/bash"]
    namespace: kube-system
Defensive patterns

Strategy: retry

Validate before calling

// preflight: confirm the shell image is pullable and node schedulable before shelling
if err := kubectl.CanPull(ctx, cfg.Image); err != nil {
    return fmt.Errorf("shell image %s not pullable: %w", cfg.Image, err)
}
if nodeCordoned(node) {
    return fmt.Errorf("node %s is cordoned", node)
}

Prevention

When it happens

Trigger: Pressing the node shell key with featureGates.nodeShell enabled when the shell pod image cannot be pulled (air-gapped registry), the node is unschedulable/cordoned/full (Pending), RBAC blocks pod creation in kube-system, or the launch is slow enough to blow the context timeout.

Common situations: Air-gapped clusters that cannot pull the default shell image; custom shellPod image misconfigured in k9s config; nodes with taints tolerating nothing; strict PodSecurity/Admission blocking the privileged pod.

Related errors


AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15). Data as JSON: /api/errors/c930080491a2825c. Report an issue: GitHub.