{"record":{"id":"a8608d7ab4b9bdfc","repo":"hashicorp/nomad","slug":"job-is-missing-id","errorCode":null,"errorMessage":"job is missing ID","messagePattern":"job is missing ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/jobs.go","lineNumber":505,"sourceCode":"}\n\n// PlanOptions is used to pass through job planning parameters\ntype PlanOptions struct {\n\tDiff           bool\n\tPolicyOverride bool\n}\n\nfunc (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) {\n\topts := PlanOptions{Diff: diff}\n\treturn j.PlanOpts(job, &opts, q)\n}\n\nfunc (j *Jobs) PlanOpts(job *Job, opts *PlanOptions, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) {\n\tif job == nil {\n\t\treturn nil, nil, errors.New(\"must pass non-nil job\")\n\t}\n\tif job.ID == nil {\n\t\treturn nil, nil, errors.New(\"job is missing ID\")\n\t}\n\n\t// Setup the request\n\treq := &JobPlanRequest{\n\t\tJob: job,\n\t}\n\tif opts != nil {\n\t\treq.Diff = opts.Diff\n\t\treq.PolicyOverride = opts.PolicyOverride\n\t}\n\n\tvar resp JobPlanResponse\n\twm, err := j.client.put(\"/v1/job/\"+url.PathEscape(*job.ID)+\"/plan\", req, &resp, q)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn &resp, wm, nil\n}","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/jobs.go#L487-L523","documentation":"Guard in Jobs.PlanOpts: the job was provided but its ID field is nil, so there is no job to plan. Set Job.ID before calling Plan/PlanOpts.","triggerScenarios":"Constructing a Job struct manually (e.g. api.NewJob or &Job{Name: ...}) and forgetting to set ID; parsing a job HCL/JSON spec that omits the 'id' field when the Name is present.","commonSituations":"Hand-built jobs in tests or tools; job spec templates missing the id field; code that copies a Job struct but drops the ID pointer.","solutions":["Set job.ID before calling PlanOpts, e.g. id := \"my-job\"; job.ID = &id","If the job spec uses Name as the ID, copy it: job.ID = job.Name","Validate the parsed job spec file includes an 'id' field"],"exampleFix":"// before\njob := &Job{Name: stringPtr(\"example\")}\nj.PlanOpts(job, &opts, q)\n// after\njob := &Job{Name: stringPtr(\"example\")}\njob.ID = job.Name // or stringPtr(\"example\")\nj.PlanOpts(job, &opts, q)","handlingStrategy":"validation","validationCode":"func jobHasID(job *api.Job) bool { return job != nil && job.ID != nil && *job.ID != \"\" }","typeGuard":"func jobHasID(j *api.Job) (*api.Job, bool) {\n    if j == nil || j.ID == nil || *j.ID == \"\" { return nil, false }\n    return j, true\n}","tryCatchPattern":"resp, _, err := jobs.PlanOpts(job, &opts, q)\nif err != nil && strings.Contains(err.Error(), \"missing ID\") {\n    return fmt.Errorf(\"job %q has no ID set; check the job spec\", job.Name)\n}","preventionTips":["Set ID immediately after constructing a Job (NewJob does this)","Validate parsed job spec files contain an 'id' field","When ID mirrors Name, assign job.ID = job.Name"],"tags":["go","nomad","jobs","missing-field","client-validation"],"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"}