GoogleContainerTools/skaffold · warning

port forwarding %v got terminated: output: %s

Error message

port forwarding %v got terminated: output: %s

What it means

The forward loop detects that its kubectl port-forward process terminated (scanning output or cmd.Wait error). It logs the buffered kubectl output and, unless the output contains "address already in use" (a transient condition the loop retries), it sends this error on errChan without blocking. It means the port-forward tunnel to the pod died and will be re-established by the forwarder's retry loop.

Source

Thrown at pkg/skaffold/kubernetes/portforward/kubectl_forwarder.go:167

			time.Sleep(500 * time.Millisecond)
			continue
		}

		// Kill kubectl on port forwarding error logs
		go k.monitorLogs(ctx, &buf, cmd, pfe, errChan)
		if err := cmd.Wait(); err != nil {
			if ctx.Err() == context.Canceled {
				log.Entry(ctx).Debugf("terminated %v due to context cancellation", pfe)
				return
			}
			// To make sure that the log monitor gets cleared up
			cancel()

			s := buf.String()
			log.Entry(ctx).Debugf("port forwarding %v got terminated: %s, output: %s", pfe, err, s)
			if !strings.Contains(s, "address already in use") {
				select {
				case errChan <- fmt.Errorf("port forwarding %v got terminated: output: %s", pfe, s):
				default:
				}
			}
			time.Sleep(500 * time.Millisecond)
		}
	}
}

func portForwardArgs(ctx context.Context, kubeContext string, pfe *portForwardEntry) []string {
	args := []string{"--pod-running-timeout", "1s", "--namespace", pfe.resource.Namespace}

	_, disableServiceForwarding := os.LookupEnv("SKAFFOLD_DISABLE_SERVICE_FORWARDING")
	switch {
	case pfe.resource.Type == "service" && !disableServiceForwarding:
		// Services need special handling: https://github.com/GoogleContainerTools/skaffold/issues/4522
		podName, remotePort, err := findNewestPodForSvc(ctx, kubeContext, pfe.resource.Namespace, pfe.resource.Name, pfe.resource.Port)
		if err == nil {
			args = append(args, fmt.Sprintf("pod/%s", podName), fmt.Sprintf("%d:%d", pfe.localPort, remotePort))

View on GitHub (pinned to a1189de023)

Solutions

  1. Check the `output:` portion of the message for kubectl's actual failure reason (e.g. connection refused, pod not found)
  2. Verify the target pod is running: kubectl get pod <pod> -n <ns>
  3. If the pod was restarted, the forwarder typically retries automatically — wait or restart skaffold dev
  4. Check network/VPN stability to the cluster; transient drops kill the tunnel
Defensive patterns

Strategy: retry

Validate before calling

// verify the target pod is ready before initiating the port-forward
pod, err := clientset.CoreV1().Pods(ns).Get(ctx, podName, metav1.GetOptions{})
if err != nil || pod.Status.Phase != corev1.PodRunning {
	return fmt.Errorf("pod %s not ready for port-forward", podName)
}

Try / catch

errChan := make(chan error, 1)
// forwarder sends termination errors here non-blocking
select {
case err := <-errChan:
	if strings.Contains(err.Error(), "got terminated") {
		// forwarder retries automatically; log and wait for re-establishment
	}
case <-ctx.Done():
}

Prevention

When it happens

Trigger: kubectl port-forward process exits: pod restarted/deleted during port-forward, network drop, connection to the pod refused, context timeout/cancellation propagated, or kubectl binary failure.

Common situations: Pod crashes or gets rescheduled while dev-loop is running; cluster node reboot; VPN/network interruption; target pod's container port stops listening.

Related errors


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