{"record":{"id":"b56e0c44bddff29d","repo":"hashicorp/nomad","slug":"unknown-new-job-status-q","errorCode":null,"errorMessage":"unknown new job status %q","messagePattern":"unknown new job status %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/state/state_store.go","lineNumber":5570,"sourceCode":"\t\t\tcase structs.JobStatusRunning:\n\t\t\t\tchildren.Running--\n\t\t\tcase structs.JobStatusDead:\n\t\t\t\tchildren.Dead--\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unknown old job status %q\", oldStatus)\n\t\t\t}\n\t\t}\n\n\t\t// Increment new status\n\t\tswitch newStatus {\n\t\tcase structs.JobStatusPending:\n\t\t\tchildren.Pending++\n\t\tcase structs.JobStatusRunning:\n\t\t\tchildren.Running++\n\t\tcase structs.JobStatusDead:\n\t\t\tchildren.Dead++\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown new job status %q\", newStatus)\n\t\t}\n\n\t\t// Update the index\n\t\tpSummary.ModifyIndex = index\n\n\t\t// Insert the summary\n\t\tif err := txn.Insert(\"job_summary\", pSummary); err != nil {\n\t\t\treturn fmt.Errorf(\"job summary insert failed: %v\", err)\n\t\t}\n\t\tif err := txn.Insert(\"index\", &IndexEntry{\"job_summary\", index}); err != nil {\n\t\t\treturn fmt.Errorf(\"index update failed: %v\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *StateStore) getJobStatus(txn *txn, job *structs.Job, evalDelete bool) (string, error) {\n\t// System, Periodic and Parameterized jobs are running until explicitly","sourceCodeStart":5552,"sourceCodeEnd":5588,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store.go#L5552-L5588","documentation":"Counterpart to the old-status error: returned by setJobSummary's increment switch when newStatus is not one of the three valid JobStatus constants (Pending, Running, Dead). The parent job summary's child counters cannot be updated for an unknown status, so the transaction aborts. It protects summary accounting invariants from invalid status values.","triggerScenarios":"setJobStatus computes a new status (possibly via getJobStatus with evalDelete) and passes a value outside {pending, running, dead} into setJobSummary's newStatus switch.","commonSituations":"Patched/forked Nomad builds introducing extra statuses, empty status from logic bugs, or state produced by incompatible versions.","solutions":["Inspect %q in the message to see the invalid status string","Constrain status assignment to the structs.JobStatus* constants","Fix the getJobStatus/caller logic producing the invalid value","Restore a valid snapshot if state was externally modified"],"exampleFix":"// before\nreturn \"stopping\", nil // invalid status\n// after\nreturn structs.JobStatusDead, nil","handlingStrategy":"validation","validationCode":"// Guard newStatus before status transitions\nif !isKnownStatus(newStatus) {\n    return fmt.Errorf(\"refusing transition to unknown status %q\", newStatus)\n}","typeGuard":"func isKnownStatus(s string) bool {\n    switch s {\n    case structs.JobStatusPending, structs.JobStatusRunning, structs.JobStatusDead:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"unknown new job status\") {\n    return fmt.Errorf(\"invalid computed status; check getJobStatus logic: %w\", err)\n}","preventionTips":["Ensure getJobStatus only returns the three valid statuses","Add unit tests covering status transition switches","Avoid custom statuses in patched builds","Validate state imported from other sources"],"tags":["nomad","state-store","job-status","validation"],"backgroundTag":"unknown-job-status-value","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"}