GoogleContainerTools/skaffold · error

initializing deployment watcher: %s

Error message

initializing deployment watcher: %s

What it means

WaitForDeploymentToStabilize starts a Watch on the AppsV1 Deployments API for the target namespace; if that watch request fails it is wrapped as 'initializing deployment watcher: %s'. The failure happens before any stability evaluation, so it reflects API-server access issues (connectivity, auth, RBAC) for the deployments resource.

Source

Thrown at pkg/skaffold/kubernetes/wait.go:143

			}
		}
		return false, nil
	})
}

// WaitForDeploymentToStabilize waits until the Deployment has a matching generation/replica count between spec and status.
func WaitForDeploymentToStabilize(ctx context.Context, c kubernetes.Interface, ns, name string, timeout time.Duration) error {
	log.Entry(ctx).Infof("Waiting for %s to stabilize", name)

	fields := fields.Set{
		"metadata.name":      name,
		"metadata.namespace": ns,
	}
	w, err := c.AppsV1().Deployments(ns).Watch(ctx, metav1.ListOptions{
		FieldSelector: fields.AsSelector().String(),
	})
	if err != nil {
		return fmt.Errorf("initializing deployment watcher: %s", err)
	}

	return watchUntilTimeout(ctx, timeout, w, func(event *watch.Event) (bool, error) {
		if event.Type == watch.Deleted {
			return false, apierrs.NewNotFound(schema.GroupResource{Resource: "deployments"}, "")
		}

		if dp, ok := event.Object.(*appsv1.Deployment); ok {
			if dp.Name == name && dp.Namespace == ns &&
				dp.Generation <= dp.Status.ObservedGeneration &&
				*(dp.Spec.Replicas) == dp.Status.Replicas {
				return true, nil
			}
			glog.Infof("Waiting for deployment %s to stabilize, generation %v observed generation %v spec.replicas %d status.replicas %d",
				name, dp.Generation, dp.Status.ObservedGeneration, *(dp.Spec.Replicas), dp.Status.Replicas)
		}
		return false, nil
	})

View on GitHub (pinned to a1189de023)

Solutions

  1. Verify access: `kubectl get deployments -n <ns>` with the same credentials; fix kubeconfig if it fails
  2. Grant RBAC watch on deployments: add apps/deployments with get,list,watch verbs to the role binding
  3. Refresh credentials (re-authenticate with the cloud provider, update the token)
  4. Check API-server reachability/VPN and retry

Example fix

// before (RBAC)
resources: ["pods"]
// after
resources: ["pods", "deployments"]
Defensive patterns

Strategy: retry

Validate before calling

// check deployments watch permission up front
_, err := client.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{})
if err != nil {
    return fmt.Errorf("deployments API not accessible in %s: %w", ns, err)
}

Try / catch

err := kubernetes.WaitForDeploymentToStabilize(ctx, client, ns, name, timeout)
if err != nil {
    if apierrors.IsForbidden(err) || apierrors.IsUnauthorized(err) {
        if rerr := refreshCredentials(ctx); rerr == nil {
            err = kubernetes.WaitForDeploymentToStabilize(ctx, client, ns, name, timeout)
        }
    }
}
return err

Prevention

When it happens

Trigger: Calling WaitForDeploymentToStabilize when c.AppsV1().Deployments(ns).Watch() errors: API server unreachable, expired credentials, or RBAC denying watch on deployments in namespace ns.

Common situations: Service account limited to pods only (no deployments RBAC) in a hardened cluster; token expiry during a long session; kubeconfig pointing at the wrong namespace/cluster; flaky cluster networking in CI.

Related errors


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