{"record":{"id":"3037c9a01e033a76","repo":"hashicorp/nomad","slug":"job-type-q-does-not-allow-migrate-block","errorCode":null,"errorMessage":"Job type %q does not allow migrate block","messagePattern":"Job type %q does not allow migrate block","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":7244,"sourceCode":"\t\tdefault:\n\t\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"Job type %q does not allow update block\", j.Type))\n\t\t}\n\t\tif err := u.Validate(); err != nil {\n\t\t\tmErr = multierror.Append(mErr, err)\n\t\t}\n\t}\n\n\t// Validate the migration strategy\n\tswitch j.Type {\n\tcase JobTypeService:\n\t\tif tg.Migrate != nil {\n\t\t\tif err := tg.Migrate.Validate(); err != nil {\n\t\t\t\tmErr = multierror.Append(mErr, err)\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tif tg.Migrate != nil {\n\t\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"Job type %q does not allow migrate block\", j.Type))\n\t\t}\n\t}\n\n\t// Check that there is only one leader task if any\n\ttasks := make(map[string]int)\n\tleaderTasks := 0\n\tmainTasks := 0\n\tfor idx, task := range tg.Tasks {\n\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++","sourceCodeStart":7226,"sourceCodeEnd":7262,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L7226-L7262","documentation":"Nomad job validation rejects a `migrate` block on any job type other than \"service\". The migrate stanza controls draining/reallocation of allocations on node updates and only applies to service jobs, so its presence under a batch/sysbatch or other type triggers this multierror entry in TaskGroup.Validate.","triggerScenarios":"Submitting a job whose task group defines a `migrate` stanza while `job type` is not \"service\" (e.g. batch, sysbatch).","commonSituations":"Template reuse: a migrate stanza copied from a service job into a batch job; retyping a service job to batch while keeping migration config; generated specs that always include migrate settings.","solutions":["Delete the `migrate` stanza from the task group.","Or set the job `type` back to \"service\" if migration behavior is required."],"exampleFix":"// before\ntype = \"batch\"\nmigrate {\n  max_parallel = 1\n}\n// after\ntype = \"batch\"\n# migrate block removed","handlingStrategy":"validation","validationCode":"// Go: pre-validate before submitting\nfor _, tg := range job.TaskGroups {\n  if job.Type != structs.JobTypeService && tg.Migrate != nil {\n    return fmt.Errorf(\"group %q: migrate block only valid for service jobs\", tg.Name)\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep migrate stanzas only in service job templates.","Run `nomad job validate` in CI pipelines.","Grep job repos for `migrate {` when changing job type to batch/sysbatch."],"tags":["nomad","job-validation","migrate-block","hcl"],"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"}