{"record":{"id":"732f18c0058b5233","repo":"hashicorp/nomad","slug":"auto-promote-must-be-true-for-all-groups-to-enable","errorCode":null,"errorMessage":"auto_promote must be true for all groups to enable automatic promotion","messagePattern":"auto_promote must be true for all groups to enable automatic promotion","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":4981,"sourceCode":"\t\tif err := tg.Warnings(j); err != nil {\n\t\t\touter := fmt.Errorf(\"Group %q has warnings: %v\", tg.Name, err)\n\t\t\tmErr.Errors = append(mErr.Errors, outer)\n\t\t}\n\n\t\tif u := tg.Update; u != nil {\n\t\t\thasAutoPromote = hasAutoPromote || u.AutoPromote\n\n\t\t\t// Having no canaries implies auto-promotion since there are no canaries to promote.\n\t\t\tallAutoPromote = allAutoPromote && (u.Canary == 0 || u.AutoPromote)\n\t\t}\n\t}\n\n\t// check if we have services with no shutdown delay set\n\tmErr.Errors = append(mErr.Errors, j.generateServiceShutdownDelayWarnings()...)\n\n\t// Check AutoPromote, should be all or none\n\tif hasAutoPromote && !allAutoPromote {\n\t\terr := fmt.Errorf(\"auto_promote must be true for all groups to enable automatic promotion\")\n\t\tmErr.Errors = append(mErr.Errors, err)\n\t}\n\n\t// cron -> crons\n\tif j.Periodic != nil && j.Periodic.Spec != \"\" {\n\t\terr := fmt.Errorf(\"cron is deprecated and may be removed in a future release. Use crons instead\")\n\t\tmErr.Errors = append(mErr.Errors, err)\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\n// LookupTaskGroup finds a task group by name\nfunc (j *Job) LookupTaskGroup(name string) *TaskGroup {\n\tif j == nil {\n\t\treturn nil\n\t}\n\tfor _, tg := range j.TaskGroups {","sourceCodeStart":4963,"sourceCodeEnd":4999,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L4963-L4999","documentation":"Job.Validate enforces that the update block's auto_promote flag is all-or-nothing across a job's task groups: if some groups have auto_promote=true and others do not, validation fails with 'auto_promote must be true for all groups to enable automatic promotion'. Automatic promotion of canaries only works when every group opts in.","triggerScenarios":"A job with multiple task groups using `update { auto_promote = ... }` where at least one group sets auto_promote=true and at least one leaves it false/omitted (default false).","commonSituations":"Adding a new group to an existing canary deployment without copying its update stanza; inconsistent copy-paste of update blocks; blue/green setups with mixed promotion policies.","solutions":["Set `auto_promote = true` in the update stanza of every task group.","Or set auto_promote = false everywhere (manual promotion via `nomad job promote`).","Validate the merged job spec across all groups before submitting."],"exampleFix":"// before\ngroup \"web\" { update { auto_promote = true } }\ngroup \"api\" { update { canary = 1 } } // auto_promote omitted\n// after\ngroup \"web\" { update { auto_promote = true, canary = 1 } }\ngroup \"api\" { update { auto_promote = true, canary = 1 } }","handlingStrategy":"validation","validationCode":"var any, all bool = false, true\nfor _, tg := range job.TaskGroups {\n    if tg.Update != nil && tg.Update.AutoPromote {\n        any = true\n    } else {\n        all = false\n    }\n}\nif any && !all {\n    return fmt.Errorf(\"auto_promote must be true for all groups\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use one shared update stanza definition for all groups in a job.","Audit update blocks when adding new task groups to canary jobs.","Promote policies: pick all-automatic or all-manual per job."],"tags":["nomad","deployment","auto-promote","canary"],"backgroundTag":"inconsistent-deployment-policy","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"}