{"record":{"id":"b4802251045255ff","repo":"hashicorp/nomad","slug":"unable-to-retrieve-summary-for-parent-job-v","errorCode":null,"errorMessage":"unable to retrieve summary for parent job: %v","messagePattern":"unable to retrieve summary for parent job: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/state/state_store.go","lineNumber":1977,"sourceCode":"\n// DeleteJobTxn is used to deregister a job, like DeleteJob,\n// but in a transaction.  Useful for when making multiple modifications atomically\nfunc (s *StateStore) DeleteJobTxn(index uint64, namespace, jobID string, txn Txn) error {\n\t// Lookup the node\n\texisting, err := txn.First(\"jobs\", \"id\", namespace, jobID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"job lookup failed: %v\", err)\n\t}\n\tif existing == nil {\n\t\treturn fmt.Errorf(\"job not found\")\n\t}\n\n\t// Check if we should update a parent job summary\n\tjob := existing.(*structs.Job)\n\tif job.ParentID != \"\" {\n\t\tsummaryRaw, err := txn.First(\"job_summary\", \"id\", namespace, job.ParentID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to retrieve summary for parent job: %v\", err)\n\t\t}\n\n\t\t// Only continue if the summary exists. It could not exist if the parent\n\t\t// job was removed\n\t\tif summaryRaw != nil {\n\t\t\texisting := summaryRaw.(*structs.JobSummary)\n\t\t\tpSummary := existing.Copy()\n\t\t\tif pSummary.Children != nil {\n\n\t\t\t\tmodified := false\n\t\t\t\tswitch job.Status {\n\t\t\t\tcase structs.JobStatusPending:\n\t\t\t\t\tpSummary.Children.Pending--\n\t\t\t\t\tpSummary.Children.Dead++\n\t\t\t\t\tmodified = true\n\t\t\t\tcase structs.JobStatusRunning:\n\t\t\t\t\tpSummary.Children.Running--\n\t\t\t\t\tpSummary.Children.Dead++","sourceCodeStart":1959,"sourceCodeEnd":1995,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store.go#L1959-L1995","documentation":"DeleteJobTxn (nomad/state/state_store.go:1977) wraps an error from txn.First(\"job_summary\", \"id\", namespace, job.ParentID) when a child (parameterized/dispatched) job is deleted and its parent's JobSummary must be adjusted. The summary lookup itself failed, aborting the deregistration transaction. This only happens for jobs with a non-empty ParentID.","triggerScenarios":"Deleting a dispatched/periodic child job when txn.First on the job_summary table errors (MemDB issue) — not when the parent summary is merely absent (that case is tolerated and skipped).","commonSituations":"Parent job already fully GC'd while children still exist; in-memory DB errors on servers applying deregistration; running many concurrent dispatch/stop operations on the same parent.","solutions":["Retry the deregistration; the txn rolled back atomically","Check the wrapped %v error in server logs for the root cause","Ensure parent jobs and their children are GC'd together (same eval/GC cycle)","Restart the server agent if the state store repeatedly errors"],"exampleFix":"// before\nreturn s.DeleteJobTxn(idx, ns, jobID, txn)\n// after\nerr := s.DeleteJobTxn(idx, ns, jobID, txn)\nif err != nil && strings.Contains(err.Error(), \"unable to retrieve summary for parent job\") {\n    return retryWithBackoff(func() error { return s.DeleteJobTxn(idx, ns, jobID, txn) })\n}\nreturn err","handlingStrategy":"retry","validationCode":"// ensure parent summary is retrievable before deleting a child\nif job.ParentID != \"\" {\n    parent, err := stateStore.JobByID(nil, ns, job.ParentID)\n    if err != nil { return err } // read path broken; delete would fail the same way\n    _ = parent\n}","typeGuard":null,"tryCatchPattern":"if err := s.DeleteJobTxn(idx, ns, jobID, txn); err != nil {\n    if strings.Contains(err.Error(), \"unable to retrieve summary for parent job\") {\n        return retry(3, backoff, func() error { return s.DeleteJobTxn(idx, ns, jobID, txn) })\n    }\n    return err\n}","preventionTips":["GC parent jobs and their dispatched children together","Retry — the failed txn rolls back atomically","Inspect the wrapped %v to separate MemDB faults from logic bugs","Avoid hand-edited state snapshots"],"tags":["state-store","job-summary","parent-job"],"backgroundTag":"memdb-lookup-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}