GoogleContainerTools/skaffold · error · CleanupErr
strings.Join(errMsgs, "\n") (joined helm cleanup error messa
Error message
strings.Join(errMsgs, "\n") (joined helm cleanup error messages)
What it means
Helm deployer Cleanup runs cleanup commands (e.g. helm delete/hooks) for each release; if any sub-command fails, all messages are collected into errMsgs and joined with newlines, then wrapped via deployerr.CleanupErr. The resulting error text is a multi-line aggregation of every helm failure encountered during cleanup.
Source
Thrown at pkg/skaffold/deploy/helm/helm.go:480
}
args := []string{}
if dryRun {
args = append(args, "get", "manifest")
} else {
args = append(args, "delete")
}
args = append(args, releaseName)
if namespace != "" {
args = append(args, "--namespace", namespace)
}
if err := helm.Exec(ctx, h, out, false, nil, args...); err != nil {
errMsgs = append(errMsgs, err.Error())
}
}
if len(errMsgs) != 0 {
return deployerr.CleanupErr(errors.New(strings.Join(errMsgs, "\n")))
}
return nil
}
func (h *Deployer) HasRunnableHooks() bool {
return len(h.LegacyHelmDeploy.LifecycleHooks.PreHooks) > 0 || len(h.LegacyHelmDeploy.LifecycleHooks.PostHooks) > 0
}
func (h *Deployer) PreDeployHooks(ctx context.Context, out io.Writer) error {
childCtx, endTrace := instrumentation.StartTrace(ctx, "Deploy_PreHooks")
if err := h.hookRunner.RunPreHooks(childCtx, out); err != nil {
endTrace(instrumentation.TraceEndError(err))
return err
}
endTrace()
return nil
}
View on GitHub (pinned to a1189de023)
Solutions
- Read each line of the joined message to see which release/step failed
- If the release is already gone, treat it as done or delete the release entry from state; rerun with the release name removed from skaffold.yaml
- Re-check cluster connectivity and kubeconfig credentials (kubectl get ns) then retry cleanup
- Run the failing helm command manually with --debug to get the root cause
Example fix
// before (release already deleted, cleanup fails) skaffold delete // after (skip already-deleted release or clean state) helm list -n mynamespace # confirm release absent skaffold delete --cue-... # or remove stale release from deploy state # alternatively: kubectl delete job/servicemanual leftovers manually
Defensive patterns
Strategy: try-catch
Validate before calling
// before cleanup, check the release exists:
rel := "<release>"
out, err := exec.Command("helm", "status", rel, "-n", ns).CombinedOutput()
releaseExists := err == nil Try / catch
err := d.Cleanup(ctx, out)
if err != nil {
for _, msg := range strings.Split(err.Error(), "\n") {
log.Printf("helm cleanup failure: %s", msg)
if strings.Contains(msg, "release: not found") {
log.Println("release already removed; treating as cleaned up")
}
}
} Prevention
- Verify releases with `helm list` before running skaffold delete/cleanup
- Keep kubeconfig credentials valid during long CI jobs
- Avoid manual `helm delete` on releases managed by skaffold
When it happens
Trigger: Calling Cleanup on a Helm deployer where one or more helm Exec invocations (e.g. 'helm delete' for a release, or hook executions) return non-zero exit codes.
Common situations: Release already deleted manually via helm CLI so 'helm delete' fails with 'release: not found'; cluster unreachable or credentials expired; helm hooks failing during uninstall; RBAC restrictions preventing deletion.
Related errors
- failed to deploy: %w
- unable to connect to Kubernetes: %w
- cannot parse the release name template: %w
- could not prepare `skaffold filter`: %w
- error decoding parsed yaml: %s
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/5a8a84b37d7aaff7.
Report an issue: GitHub.