{"record":{"id":"5fa6730f2425adac","repo":"hashicorp/nomad","slug":"missing-job-datacenters","errorCode":null,"errorMessage":"Missing job datacenters","messagePattern":"Missing job datacenters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":4767,"sourceCode":"\t}\n\tif j.Name == \"\" {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Missing job name\"))\n\t} else if strings.Contains(j.Name, \"\\000\") {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Job Name contains a null character\"))\n\t}\n\n\tif j.Namespace == \"\" {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Job must be in a namespace\"))\n\t}\n\tswitch j.Type {\n\tcase JobTypeCore, JobTypeService, JobTypeBatch, JobTypeSystem, JobTypeSysBatch:\n\tcase \"\":\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Missing job type\"))\n\tdefault:\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Invalid job type: %q\", j.Type))\n\t}\n\tif len(j.Datacenters) == 0 && !j.IsMultiregion() {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Missing job datacenters\"))\n\t} else {\n\t\tfor _, v := range j.Datacenters {\n\t\t\tif v == \"\" {\n\t\t\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Job datacenter must be non-empty string\"))\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(j.TaskGroups) == 0 {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Missing job task groups\"))\n\t}\n\tfor idx, constr := range j.Constraints {\n\t\tif err := constr.Validate(); err != nil {\n\t\t\touter := fmt.Errorf(\"Constraint %d validation failed: %s\", idx+1, err)\n\t\t\tmErr.Errors = append(mErr.Errors, outer)\n\t\t}\n\t}\n\tif j.Type == JobTypeSystem {","sourceCodeStart":4749,"sourceCodeEnd":4785,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L4749-L4785","documentation":"Job.Validate() requires at least one datacenter unless the job is multiregion. Datacenters constrain where the scheduler places allocations; with none specified the job cannot be placed, so the spec is invalid.","triggerScenarios":"Submitting a job whose `datacenters` list is empty/absent and j.IsMultiregion() is false — via nomad job run, POST /v1/jobs, or Validate() on a programmatically built job.","commonSituations":"Forgetting `datacenters = [\"dc1\"]` when writing a job file; CLI-generated templates stripped of the stanza; jobs moved from a multiregion setup back to single-region without adding datacenters.","solutions":["Add `datacenters = [\"dc1\"]` (matching a datacenter your agents report) to the job file","Convert the job to multiregion if it genuinely targets multiple regions","Ensure job.Datacenters is populated when constructing the job in Go"],"exampleFix":"// before\njob \"web-app\" {\n  type = \"service\"\n  group \"web\" { ... }\n}\n// after\njob \"web-app\" {\n  type = \"service\"\n  datacenters = [\"dc1\"]\n  group \"web\" { ... }\n}","handlingStrategy":"validation","validationCode":"if len(j.Datacenters) == 0 && !j.IsMultiregion() {\n    return fmt.Errorf(\"job must specify at least one datacenter\")\n}","typeGuard":"func hasDatacenters(j *structs.Job) bool { return j.IsMultiregion() || len(j.Datacenters) > 0 }","tryCatchPattern":"if err := job.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"Missing job datacenters\") {\n        return fmt.Errorf(\"add datacenters = [\\\"dc1\\\"] to the job: %w\", err)\n    }\n}","preventionTips":["List datacenters matching nomad node status output","Keep the datacenters stanza in all single-region job templates","Run nomad job validate in CI"],"tags":["nomad","go","validation","scheduling"],"backgroundTag":"missing-required-argument","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"}