derailed/k9s · error

unable to forward port because pod is not running. Current s

Error message

unable to forward port because pod is not running. Current status=%v

What it means

Start rejects the session unless the target pod's status.phase is Running. Pending, Succeeded, Failed, or Unknown pods cannot serve a tunnel, so the DAO fails fast and includes the observed phase in the message.

Source

Thrown at internal/dao/port_forwarder.go:141

	ns, n := client.Namespaced(path)
	auth, err := p.Client().CanI(ns, client.PodGVR, n, client.GetAccess)
	if err != nil {
		return nil, err
	}
	if !auth {
		return nil, fmt.Errorf("user is not authorized to get pods")
	}

	podName := strings.Split(n, "|")[0]
	var res Pod
	res.Init(p, client.PodGVR)
	pod, err := res.GetInstance(client.FQN(ns, podName))
	if err != nil {
		return nil, err
	}
	if pod.Status.Phase != v1.PodRunning {
		return nil, fmt.Errorf("unable to forward port because pod is not running. Current status=%v", pod.Status.Phase)
	}

	auth, err = p.Client().CanI(ns, client.PodGVR.WithSubResource("portforward"), "", []string{client.CreateVerb})
	if err != nil {
		return nil, err
	}
	if !auth {
		return nil, fmt.Errorf("user is not authorized to update portforward")
	}

	cfg, err := p.Client().RestConfig()
	if err != nil {
		return nil, err
	}
	cfg.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
	cfg.APIPath = "/api"
	codec, _ := codec()
	cfg.NegotiatedSerializer = codec.WithoutConversion()

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Wait for readiness: kubectl wait --for=condition=ready pod/<name> --timeout=90s
  2. Diagnose why it is not Running: kubectl describe pod <name> (events, init containers, probes)
  3. For completed Job pods, run a new pod instead of forwarding to the finished one

Example fix

// before
pf, err := pfMgr.Start(path, tunnel) // fails on Pending pod

// after
pod, _ := podDAO.GetInstance(fqn)
if pod == nil || pod.Status.Phase != v1.PodRunning {
    return fmt.Errorf("wait for pod %q to be Running before forwarding (phase=%v)", fqn, pod.Status.Phase)
}
pf, err := pfMgr.Start(path, tunnel)
Defensive patterns

Strategy: validation

Validate before calling

var res dao.Pod
res.Init(client, client.PodGVR)
pod, err := res.GetInstance(fqn)
if err != nil { return err }
if pod.Status.Phase != v1.PodRunning {
    return fmt.Errorf("pod phase %s; wait for Running", pod.Status.Phase)
}

Type guard

func isRunnable(p *v1.Pod) bool {
    return p != nil && p.Status.Phase == v1.PodRunning
}

Try / catch

if _, err := pf.Start(path, tunnel); err != nil {
    if strings.Contains(err.Error(), "pod is not running") {
        // wait for ready condition, then retry Start once
    }
}

Prevention

When it happens

Trigger: Forwarding while the pod is Pending (image pull, scheduling, init containers), Succeeded/Failed (completed Job pods), or Unknown (node unreachable).

Common situations: Forwarding immediately after a rollout before readiness; forwarding to one-shot Job pods that already finished; node NotReady leaving pods in Unknown.

Related errors


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