helm/helm · error
expected %s to be a *v1.Pod, got %T
Error message
expected %s to be a *v1.Pod, got %T
What it means
Internal invariant failure in legacyWaiter.waitForPodSuccess (pkg/kube/wait.go:324). The watcher routed an event object as a Pod (Kind 'Pod'), but it did not decode to *corev1.Pod, so the type assertion fails. Like the Job variant, it indicates kind/type confusion in the watch stream rather than a workload problem.
Source
Thrown at pkg/kube/wait.go:324
if c.Type == batchv1.JobComplete && c.Status == "True" {
return true, nil
} else if c.Type == batchv1.JobFailed && c.Status == "True" {
slog.Error("job failed", "job", name, "reason", c.Reason)
return true, fmt.Errorf("job %s failed: %s", name, c.Reason)
}
}
slog.Debug("job status update", "job", name, "active", o.Status.Active, "failed", o.Status.Failed, "succeeded", o.Status.Succeeded)
return false, nil
}
// waitForPodSuccess is a helper that waits for a pod to complete.
//
// This operates on an event returned from a watcher.
func (hw *legacyWaiter) waitForPodSuccess(obj runtime.Object, name string) (bool, error) {
o, ok := obj.(*corev1.Pod)
if !ok {
return true, fmt.Errorf("expected %s to be a *v1.Pod, got %T", name, obj)
}
switch o.Status.Phase {
case corev1.PodSucceeded:
slog.Debug("pod succeeded", "pod", o.Name)
return true, nil
case corev1.PodFailed:
slog.Error("pod failed", "pod", o.Name)
return true, fmt.Errorf("pod %s failed", o.Name)
case corev1.PodPending:
slog.Debug("pod pending", "pod", o.Name)
case corev1.PodRunning:
slog.Debug("pod running", "pod", o.Name)
case corev1.PodUnknown:
slog.Debug("pod unknown", "pod", o.Name)
}
return false, nilView on GitHub (pinned to 2a29f1770b)
Solutions
- Check for CRDs whose kind is 'Pod' (kubectl get crds) and rename them.
- Clear the discovery/cache and retry after cluster upgrades settle.
- Prefer the status-watcher wait path (GroupKind-based) in SDK code instead of the legacy Pod watcher.
Defensive patterns
Strategy: type-guard
Type guard
func isCorePod(obj runtime.Object) bool {
_, ok := obj.(*corev1.Pod)
return ok
} Try / catch
if err != nil && strings.Contains(err.Error(), "to be a *v1.Pod") {
// kind/type confusion: check CRDs named Pod, refresh discovery, retry
} Prevention
- Avoid CRD kinds that shadow core Pod.
- Re-run after discovery caches refresh post-upgrade.
When it happens
Trigger: Rare: requires an event identified as a Pod that decodes to another Go type — custom CRD with kind 'Pod', schema/discovery cache mismatch after cluster or Helm upgrades, or a serializer picking the wrong registered type.
Common situations: CRDs shadowing core 'Pod' kind; stale client-side discovery caches; mid-upgrade control planes serving inconsistent schemas.
Related errors
- expected %s to be a *batch.Job, got %T
- unable to build kubernetes objects for delete: %w
- unable to get apiresource from unstructured: %s: %w
- serializing live configuration: %w
- %w: at least one field was changed: apiVersion, kind or name
AI-assisted analysis of helm/helm@2a29f1770b (2026-08-15).
Data as JSON: /api/errors/45d2aee45cacb580.
Report an issue: GitHub.