{"record":{"id":"2450f55f35f25e5e","repo":"hashicorp/nomad","slug":"task-can-only-ask-for-cpu-or-cores-resource-n","errorCode":null,"errorMessage":"Task can only ask for 'cpu' or 'cores' resource, not both.","messagePattern":"Task can only ask for 'cpu' or 'cores' resource, not both\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":2424,"sourceCode":"\t}\n}\n\n// DiskInBytes returns the amount of disk resources in bytes.\nfunc (r *Resources) DiskInBytes() int64 {\n\treturn int64(r.DiskMB * BytesInMegabyte)\n}\n\nconst (\n\t// MemoryNoLimit is a sentinel value indicating there is no upper hard\n\t// memory limit\n\tMemoryNoLimit = -1\n)\n\nfunc (r *Resources) Validate() error {\n\tvar mErr multierror.Error\n\n\tif r.Cores > 0 && r.CPU > 0 {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Task can only ask for 'cpu' or 'cores' resource, not both.\"))\n\t}\n\n\tif r.Cores < 0 {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"cores value (%d) cannot be negative\", r.Cores))\n\t}\n\n\tif err := r.MeetsMinResources(); err != nil {\n\t\tmErr.Errors = append(mErr.Errors, err)\n\t}\n\n\t// Ensure the task isn't asking for disk resources\n\tif r.DiskMB > 0 {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Task can't ask for disk resources, they have to be specified at the task group level.\"))\n\t}\n\n\t// Ensure devices are valid\n\tdevices := set.New[string](len(r.Devices))\n\tfor i, d := range r.Devices {","sourceCodeStart":2406,"sourceCodeEnd":2442,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L2406-L2442","documentation":"Appended by Resources.Validate when a task resource block sets both CPU (MHz) and Cores. Nomad permits either the legacy cpu-based accounting or the newer cores-based one, never both on the same task.","triggerScenarios":"A task resources block (or Resources struct) with cores > 0 and cpu > 0 simultaneously during job validation.","commonSituations":"Jobs written after Nomad 1.1 introduced cores, where a base template set cpu and the operator added cores; tooling merging resource defaults with overrides.","solutions":["Remove the cpu field and keep cores (recommended for whole-core granularity)","Or remove cores and keep cpu (MHz) for finer-grained sizing"],"exampleFix":"// before\nresources {\n  cpu    = 2000\n  cores  = 2\n  memory = 1024\n}\n// after\nresources {\n  cores  = 2\n  memory = 1024\n}","handlingStrategy":"validation","validationCode":"function validateCpuExclusive(resources) {\n  if ((resources.cores ?? 0) > 0 && (resources.cpu ?? 0) > 0) {\n    throw new Error(\"task resources: set either cpu (MHz) or cores, not both\");\n  }\n}","typeGuard":"function hasValidCpuSpec(r) { return !((r.cores ?? 0) > 0 && (r.cpu ?? 0) > 0); }","tryCatchPattern":"try {\n  await nomad.jobs.validate(job);\n} catch (e) {\n  if (e.message.includes(\"'cpu' or 'cores' resource, not both\")) {\n    console.error(\"Pick one CPU sizing field per task\");\n  } else throw e;\n}","preventionTips":["Standardize on one CPU sizing convention (cores for whole-core, cpu for MHz) org-wide","Watch for template layering that adds cores on top of a cpu default","Keep base resource templates with only one CPU field set"],"tags":["nomad","resources","cpu","job-validation"],"backgroundTag":"mutually-exclusive-fields","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"}