{"record":{"id":"0f95d5df5eefa8dc","repo":"derailed/k9s","slug":"d-pods-failed","errorCode":null,"errorMessage":"%d pods failed","messagePattern":"(.+?) pods failed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/render/job.go","lineNumber":91,"sourceCode":"\t\tjob.Namespace,\n\t\tjob.Name,\n\t\tcomputeVulScore(job.Namespace, job.Labels, &job.Spec.Template.Spec),\n\t\tready,\n\t\ttoDuration(&job.Status),\n\t\tjobSelector(&job.Spec),\n\t\tcc,\n\t\tii,\n\t\tAsStatus(j.diagnose(ready, &job.Status)),\n\t\tToAge(job.GetCreationTimestamp()),\n\t}\n\n\treturn nil\n}\n\nfunc (Job) diagnose(ready string, status *batchv1.JobStatus) error {\n\ttokens := strings.Split(ready, \"/\")\n\tif tokens[0] != tokens[1] && status.Failed > 0 {\n\t\treturn fmt.Errorf(\"%d pods failed\", status.Failed)\n\t}\n\treturn nil\n}\n\n// ----------------------------------------------------------------------------\n// Helpers...\n\nconst maxShow = 2\n\nfunc toContainers(p *v1.PodSpec) (containers, images string) {\n\tcc, ii := parseContainers(p.InitContainers)\n\tcn, ci := parseContainers(p.Containers)\n\n\tcc, ii = append(cc, cn...), append(ii, ci...)\n\n\t// Limit to 2 of each...\n\tif len(cc) > maxShow {\n\t\tcc = append(cc[:2], \"(+\"+strconv.Itoa(len(cc)-maxShow)+\")...\")","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/render/job.go#L73-L109","documentation":"Job.diagnose splits the ready column '<succeeded>/<desired>'; when the counts differ AND status.failed > 0 it reports 'N pods failed'. It surfaces batch Jobs whose pods have actually failed (not merely still running) — backoff/restart territory.","triggerScenarios":"Job pods exiting non-zero (app bug, bad args, missing config); image pull failures recorded as pod failures; completions > parallelism mid-run with early failures; backoffLimit not yet reached.","commonSituations":"One-shot migrate/batch jobs with wrong env vars; OOMKilled workers (memory limits too low); Jobs racing dependencies (DB not up); cronjobs hitting transient API errors.","solutions":["kubectl describe job <name> and read the events (BackoffLimitExceeded etc.)","Fetch failed pod logs: kubectl logs <pod> --previous to see the actual error","Fix the root cause (env, command, limits) and re-run: kubectl delete job <name> && kubectl apply -f job.yaml","Raise backoffLimit / set restartPolicy: OnFailure only if failures are genuinely transient"],"exampleFix":"# before: app needs DB URI, pods fail instantly\ncontainers:\n- name: migrate\n  image: app:v1\n# after\ncontainers:\n- name: migrate\n  image: app:v1\n  env:\n  - name: DATABASE_URL\n    value: postgres://...","handlingStrategy":"fallback","validationCode":"if job.Status.Failed == 0 {\n\t// no failed pods; skip failure handling\n}","typeGuard":null,"tryCatchPattern":"Consume the error as status text; on display, trigger log retrieval for failed pods rather than retrying the Job blindly.","preventionTips":["Validate env/config before submitting one-shot Jobs","Set backoffLimit and restartPolicy deliberately for transient-dependency Jobs","Alert on Job failure counts, and keep --previous logs accessible"],"tags":["job","batch","health","kubernetes"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}