{"record":{"id":"6bb16af177f6d29f","repo":"GoogleContainerTools/skaffold","slug":"cleaning-up-deployed-job","errorCode":null,"errorMessage":"cleaning up deployed job","messagePattern":"cleaning up deployed job","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/verify/k8sjob/verify.go","lineNumber":331,"sourceCode":"\n// Cleanup deletes what was verified by calling Verify.\nfunc (v *Verifier) Cleanup(ctx context.Context, out io.Writer, dryRun bool) error {\n\tinstrumentation.AddAttributesToCurrentSpanFromContext(ctx, map[string]string{\n\t\t\"VerifierType\": \"kubernetesCluster\",\n\t})\n\n\tclientset, err := kubernetesclient.Client(v.kubectl.KubeContext)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting Kubernetes client: %w\", err)\n\t}\n\n\tfor _, job := range v.tracker.DeployedJobs() {\n\t\t// assumes the job namespace is set and not \"\" which is the case as createJob\n\t\t// & createJobFromManifestPath set the namespace in the created Job\n\t\tnamespace := job.Namespace\n\t\tif err := k8sjobutil.ForceJobDelete(ctx, job.Name, clientset.BatchV1().Jobs(namespace), &v.kubectl); err != nil {\n\t\t\t// TODO(aaron-prindle): replace with actionable error\n\t\t\treturn errors.Wrap(err, \"cleaning up deployed job\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Dependencies lists all the files that describe what needs to be verified.\nfunc (v *Verifier) Dependencies() ([]string, error) {\n\treturn []string{}, nil\n}\n\n// TrackContainerAndJobFromBuild adds an artifact and its newly-associated container\n// to the container tracker.\nfunc (v *Verifier) TrackContainerAndJobFromBuild(artifact graph.Artifact, container tracker.Job, job *batchv1.Job) {\n\tv.tracker.Add(artifact, container, job.Namespace)\n\tv.tracker.AddJob(job)\n\tv.logger.RegisterJob(job.Name)\n}\n","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/verify/k8sjob/verify.go#L313-L349","documentation":"Skaffold's verify Cleanup wraps an error returned while force-deleting a Kubernetes Job it had deployed for verification. Cleanup iterates over the tracker's deployed jobs and calls ForceJobDelete in each job's namespace; any kubectl delete failure is wrapped as \"cleaning up deployed job\". It means a verification Job object could not be removed from the cluster, often because the cluster is unreachable or the job/namespace is gone.","triggerScenarios":"Calling Cleanup on a k8sjob verifier when k8sjobutil.ForceJobDelete fails — e.g. the kubectl client cannot reach the cluster, the Job's namespace no longer exists, the Job already disappeared with a NotFound error treated as fatal, or RBAC denies deleting batchv1 Jobs.","commonSituations":"Cluster was torn down or context switched between the verify run and cleanup; namespace was deleted out from under the job; stale kubeconfig/credentials; network partition to the API server during teardown.","solutions":["Check cluster connectivity and current kubectl context (kubectl cluster-info) and retry cleanup","Verify the job's namespace still exists and the Job name is valid; delete manually with kubectl -n <ns> delete job <name> --force --grace-period=0","Confirm RBAC allows delete on batch/jobs in that namespace","If the job is already gone (NotFound), treat cleanup as done — this is the actionable-error TODO noted in the code"],"exampleFix":"// before: wrapped opaque error\ncleanup failed: cleaning up deployed job: job.batch \"verify-abc\" not found\n// after: ignore NotFound during cleanup\nif apierrors.IsNotFound(err) { continue }\nreturn errors.Wrap(err, \"cleaning up deployed job\")","handlingStrategy":"try-catch","validationCode":"if err := exec.Command(\"kubectl\", \"cluster-info\").Run(); err != nil { return fmt.Errorf(\"cluster unreachable: %w\", err) }\nif _, err := clientset.BatchV1().Jobs(ns).Get(ctx, jobName, metav1.GetOptions{}); err != nil { /* pre-check job exists */ }","typeGuard":"func isNotFoundErr(err error) bool { return apierrors.IsNotFound(err) }","tryCatchPattern":"func safeCleanup(v *Verifier) (err error) {\n  defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"cleanup panic: %v\", r) } }()\n  return v.Cleanup(context.Background())\n}","preventionTips":["Verify kubectl context/credentials before running verify","Pre-check namespace and RBAC (delete on batch/jobs) before deploying verification jobs","Treat NotFound during cleanup as success"],"tags":["kubernetes","cleanup","job-deletion","verify"],"backgroundTag":"kubernetes-job-delete-failed","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}