{"record":{"id":"4360cb9b895697fb","repo":"hashicorp/nomad","slug":"missing-job-id-for-evaluation","errorCode":null,"errorMessage":"missing job ID for evaluation","messagePattern":"missing job ID for evaluation","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/job_endpoint.go","lineNumber":700,"sourceCode":"\tj.srv.MeasureRPCRate(\"job\", structs.RateMetricWrite, args)\n\tif authErr != nil {\n\t\treturn structs.ErrPermissionDenied\n\t}\n\tdefer metrics.MeasureSince([]string{\"nomad\", \"job\", \"evaluate\"}, time.Now())\n\n\t// Check for submit-job permissions\n\tif aclObj, err := j.srv.ResolveACL(args); err != nil {\n\t\treturn err\n\t} else if !aclObj.AllowNsOpAnyOf(args.RequestNamespace(),\n\t\tacl.NamespaceCapabilitySubmitJob,\n\t\tacl.NamespaceCapabilityEvaluateJob,\n\t) {\n\t\treturn structs.ErrPermissionDenied\n\t}\n\n\t// Validate the arguments\n\tif args.JobID == \"\" {\n\t\treturn fmt.Errorf(\"missing job ID for evaluation\")\n\t}\n\n\t// Lookup the job\n\tsnap, err := j.srv.fsm.State().Snapshot()\n\tif err != nil {\n\t\treturn err\n\t}\n\tws := memdb.NewWatchSet()\n\tjob, err := snap.JobByID(ws, args.RequestNamespace(), args.JobID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif job == nil {\n\t\treturn fmt.Errorf(\"job not found\")\n\t}\n\n\tif job.IsPeriodic() {\n\t\treturn fmt.Errorf(\"can't evaluate periodic job\")","sourceCodeStart":682,"sourceCodeEnd":718,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/job_endpoint.go#L682-L718","documentation":"The Job.Evaluate RPC forces a new evaluation for a job, and this guard rejects requests with an empty JobID before any state lookup. Nomad throws it because evaluation is always scoped to a specific job; an empty ID is an invalid client request.","triggerScenarios":"Calling the Evaluate RPC (POST /v1/job/<id>/evaluate) where the request body's JobID field is empty — typically building the JobEvaluateRequest manually instead of letting the HTTP handler populate it from the URL path.","commonSituations":"Custom automation constructing api.JobEvaluateRequest{} without setting JobID; SDK wrappers that drop the path parameter; refactored scripts after switching from job prefix endpoints.","solutions":["Set JobID on the JobEvaluateRequest (or use the HTTP endpoint path /v1/job/<id>/evaluate which fills it in)","Validate the job ID variable is non-empty before issuing the request","Use the official nomad/api client Jobs().Evaluate(id, ...) rather than hand-built RPC payloads"],"exampleFix":"// before\n_, _, err := client.Jobs().Evaluate(\"\", nil)\n// after\njobID := os.Getenv(\"NOMAD_JOB_ID\")\nif jobID == \"\" { return fmt.Errorf(\"job id required\") }\n_, _, err := client.Jobs().Evaluate(jobID, nil)","handlingStrategy":"validation","validationCode":"if jobID == \"\" {\n\treturn fmt.Errorf(\"jobID must be non-empty before calling Evaluate\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use client.Jobs().Evaluate(id, nil) so the ID comes from one parameter","Assert non-empty identifiers at automation entry points","Never hand-build JobEvaluateRequest bodies"],"tags":["nomad","validation","request-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"}