GoogleContainerTools/skaffold · error

timeout waiting for event from pod of kubernetes job: %s

Error message

timeout waiting for event from pod of kubernetes job: %s

What it means

This error fires when the 30-second timer in the pod-event wait select expires before a pod for the k8s job is observed or the context is cancelled. The library waits at most 30 seconds for the job's pod to start emitting events before giving up on attaching logs. It means the job's pod never became visible to the watcher in time.

Source

Thrown at pkg/skaffold/k8sjob/logger/log.go:195

			done := make(chan bool)
			go func() {
				for event := range w.ResultChan() {
					pod, ok := event.Object.(*corev1.Pod)
					if ok {
						podName = pod.Name
						done <- true
						break
					}
				}
			}()

			select {
			case <-ctx.Done():
				return false, fmt.Errorf("context cancelled for k8s job logging of pod of kubernetes job: %s", "id")
			case <-done:
				// Continue
			case <-time.After(30 * time.Second): // Timeout after 30 seconds
				return false, fmt.Errorf("timeout waiting for event from pod of kubernetes job: %s", id)
			}

			podLogOptions := &corev1.PodLogOptions{
				Follow: true,
			}

			// Stream the logs
			req := clientset.CoreV1().Pods(namespace).GetLogs(podName, podLogOptions)
			podLogs, err := req.Stream(ctx)
			if err != nil {
				return false, nil
			}
			defer podLogs.Close()
			io.Copy(tw, podLogs)
			l.hadLogsOutput.Store(id, true)
			return true, nil
		}); waitErr != nil {
			// Don't print errors if the user interrupted the logs

View on GitHub (pinned to a1189de023)

Solutions

  1. Increase the 30-second timeout constant in pkg/skaffold/k8sjob/logger/log.go if pulls/scheduling legitimately take longer
  2. Check the job's pod status with kubectl describe job <job> and kubectl get pods to see why no pod started (ImagePullBackOff, Unschedulable, quota)
  3. Verify the image reference is valid and pullable from the cluster
  4. Pre-pull or cache images (e.g. warm nodes or use smaller images) to speed startup
  5. Check the event watcher filters — ensure the namespace/label selector matches where the pod actually runs

Example fix

// before
case <-time.After(30 * time.Second): // Timeout after 30 seconds
    return false, fmt.Errorf("timeout waiting for event from pod of kubernetes job: %s", id)
// after
const podEventTimeout = 2 * time.Minute
case <-time.After(podEventTimeout):
Defensive patterns

Strategy: retry

Validate before calling

// Verify the job's pod exists before attaching logs
pods, err := clientset.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{
    LabelSelector: "job-name=" + jobName,
})
if err != nil || len(pods.Items) == 0 {
    return fmt.Errorf("no pod yet for job %s: %v", jobName, err)
}

Try / catch

err := attachLogs(ctx, job)
if err != nil {
    if strings.Contains(err.Error(), "timeout waiting for event") {
        // inspect pod status and retry once
        return retryWithBackoff(2, 5*time.Second, func() error { return attachLogs(ctx, job) })
    }
    return err
}

Prevention

When it happens

Trigger: The job's pod does not start within 30 seconds of the wait beginning: the job spec fails to create a pod, the image pull is slow, scheduling is pending (unschedulable node, resource quotas), or the pod name/event never matches the watcher's expectations.

Common situations: Large images requiring long pulls, cluster with no available nodes or pending resource quotas, job manifests with long backoff/startup delays, slow or overloaded API server delaying event delivery.

Understand the failure class

Related errors


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