{"record":{"id":"76e35fd0f8c0f380","repo":"hashicorp/nomad","slug":"system-jobs-may-not-have-an-affinity-block","errorCode":null,"errorMessage":"System jobs may not have an affinity block","messagePattern":"System jobs may not have an affinity block","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":4787,"sourceCode":"\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 {\n\t\tif j.Affinities != nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"System jobs may not have an affinity block\"))\n\t\t}\n\t} else {\n\t\tfor idx, affinity := range j.Affinities {\n\t\t\tif err := affinity.Validate(); err != nil {\n\t\t\t\touter := fmt.Errorf(\"Affinity %d validation failed: %s\", idx+1, err)\n\t\t\t\tmErr.Errors = append(mErr.Errors, outer)\n\t\t\t}\n\t\t}\n\t}\n\n\tif j.Type == JobTypeSystem {\n\t\tif j.Spreads != nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"System jobs may not have a spread block\"))\n\t\t}\n\t} else {\n\t\tfor idx, spread := range j.Spreads {\n\t\t\tif err := spread.Validate(); err != nil {\n\t\t\t\touter := fmt.Errorf(\"Spread %d validation failed: %s\", idx+1, err)","sourceCodeStart":4769,"sourceCodeEnd":4805,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L4769-L4805","documentation":"Job.Validate() rejects system jobs that declare any affinities: 'System jobs may not have an affinity block'. Affinities influence placement scoring among candidate nodes, which is meaningless for system jobs since they run on every eligible node.","triggerScenarios":"Registering or validating a job with type = \"system\" (j.Type == JobTypeSystem) while j.Affinities is non-nil, i.e. the job spec contains an affinity block at job or group level.","commonSituations":"Converting a service job to a system job without removing its affinity blocks, copy-pasting a service job template, or an HCL job where affinity blocks were left in place after changing the scheduler type.","solutions":["Remove all affinity blocks from the system job spec","If placement preference is needed, use node constraints (constraint blocks) with node_class/meta attributes instead","Keep affinities only on service/batch jobs","Run 'nomad job validate' to confirm the corrected spec"],"exampleFix":"// before\njob \"sys\" {\n  type = \"system\"\n  affinity {\n    attribute = \"${node.datacenter}\"\n    value     = \"dc1\"\n  }\n}\n// after\njob \"sys\" {\n  type = \"system\"\n  constraint {\n    attribute = \"${node.datacenter}\"\n    value     = \"dc1\"\n  }\n}","handlingStrategy":"validation","validationCode":"if job.Type == \"system\" && len(job.Affinities) > 0 {\n    return errors.New(\"system jobs may not declare affinities\")\n}\nreturn nil","typeGuard":null,"tryCatchPattern":"if err := job.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"affinity block\") {\n        return ErrSystemJobAffinity\n    }\n    return err\n}","preventionTips":["When changing job type to system, strip affinity and spread blocks","Maintain separate job templates for system vs service jobs","Lint job specs for affinity blocks when type=system"],"tags":["nomad","job-validation","system-job","affinity"],"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"}