{"record":{"id":"b1b90c22395a4f53","repo":"hashicorp/nomad","slug":"only-one-task-may-be-marked-as-leader","errorCode":null,"errorMessage":"Only one task may be marked as leader","messagePattern":"Only one task may be marked as leader","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":7271,"sourceCode":"\t\tif task.Name == \"\" {\n\t\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"Task %d missing name\", idx+1))\n\t\t} else if existing, ok := tasks[task.Name]; ok {\n\t\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"Task %d redefines '%s' from task %d\", idx+1, task.Name, existing+1))\n\t\t} else {\n\t\t\ttasks[task.Name] = idx\n\t\t}\n\n\t\tif task.Leader {\n\t\t\tleaderTasks++\n\t\t}\n\n\t\tif task.IsMain() {\n\t\t\tmainTasks++\n\t\t}\n\t}\n\n\tif leaderTasks > 1 {\n\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"Only one task may be marked as leader\"))\n\t}\n\n\t// A task group made up entirely of lifecycle tasks (prestart, poststart, or\n\t// poststop) has no main task to run, which is invalid.\n\tif len(tg.Tasks) > 0 && mainTasks == 0 {\n\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"Task group %s must have at least one main task\", tg.Name))\n\t}\n\n\t// Validate the volume requests\n\tvar canaries int\n\tif tg.Update != nil {\n\t\tcanaries = tg.Update.Canary\n\t}\n\tfor name, volReq := range tg.Volumes {\n\t\tif err := volReq.Validate(j.Type, tg.Count, canaries); err != nil {\n\t\t\tmErr = multierror.Append(mErr, fmt.Errorf(\n\t\t\t\t\"Task group volume validation for %s failed: %v\", name, err))\n\t\t}","sourceCodeStart":7253,"sourceCodeEnd":7289,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L7253-L7289","documentation":"TaskGroup.Validate counts tasks with `leader = true` and rejects a group with more than one leader task. Only a single task may be designated leader because Nomad uses the leader flag to decide which task's exit signals shutdown of the whole allocation.","triggerScenarios":"Submitting a job where two or more task blocks in the same group set `leader = true`.","commonSituations":"Copy-pasting a task stanza including its leader flag; misunderstanding leader semantics and marking several coordination tasks as leaders.","solutions":["Set `leader = true` on exactly one task in the group; remove the flag from the others.","If multiple tasks truly lead independent lifecycles, split them into separate task groups."],"exampleFix":"// before\ntask \"api\" { leader = true }\ntask \"worker\" { leader = true }\n// after\ntask \"api\" { leader = true }\ntask \"worker\" { }","handlingStrategy":"validation","validationCode":"// Go: at most one leader per group\nfor _, tg := range job.TaskGroups {\n  leaders := 0\n  for _, t := range tg.Tasks {\n    if t.Leader {\n      leaders++\n    }\n  }\n  if leaders > 1 {\n    return fmt.Errorf(\"group %q has %d leader tasks\", tg.Name, leaders)\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the leader flag on the task whose exit governs shutdown, typically the main server process.","Strip leader from copied task stanzas.","Document leader selection in your job templates."],"tags":["nomad","job-validation","leader-task"],"backgroundTag":"nomad-job-validation-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"}