{"record":{"id":"a796695598c624f6","repo":"hashicorp/nomad","slug":"evaluation-not-blocked","errorCode":null,"errorMessage":"evaluation not blocked","messagePattern":"evaluation not blocked","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nomad/eval_endpoint.go","lineNumber":409,"sourceCode":"\t\treturn err\n\t}\n\n\t// Look for the eval\n\tsnap, err := e.srv.fsm.State().Snapshot()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tws := memdb.NewWatchSet()\n\tout, err := snap.EvalByID(ws, eval.ID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif out == nil {\n\t\treturn fmt.Errorf(\"evaluation does not exist\")\n\t}\n\tif out.Status != structs.EvalStatusBlocked {\n\t\treturn fmt.Errorf(\"evaluation not blocked\")\n\t}\n\n\t// Reblock the eval\n\te.srv.blockedEvals.Reblock(eval, args.EvalToken)\n\treturn nil\n}\n\n// Reap is used to cleanup dead evaluations and allocations\nfunc (e *Eval) Reap(args *structs.EvalReapRequest,\n\treply *structs.GenericResponse) error {\n\n\taclObj, err := e.srv.AuthenticateServerOnly(e.ctx, args)\n\te.srv.MeasureRPCRate(\"eval\", structs.RateMetricWrite, args)\n\tif err != nil || !aclObj.AllowServerOp() {\n\t\treturn structs.ErrPermissionDenied\n\t}\n\n\tif done, err := e.srv.forward(\"Eval.Reap\", args, args, reply); done {","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/eval_endpoint.go#L391-L427","documentation":"This error is returned by the Evaluations.Reblock RPC when the evaluation being reblocked exists but its status is not 'blocked'. Reblocking is only valid for evals already in the blocked state; anything else (pending, complete, failed, cancelled) is rejected.","triggerScenarios":"Calling the Reblock RPC (or an API path that invokes it) with an eval ID whose current status is not structs.EvalStatusBlocked, e.g. the eval already completed or was cancelled between when the client saw it and when Reblock ran.","commonSituations":"Retry logic re-submitting a reblock after the eval was already reblocked or finalized; a deployment/alloc watcher acting on a stale eval ID; race conditions where the scheduler unblocked or finalized the eval concurrently.","solutions":["Fetch the eval first and confirm its Status is 'blocked' before calling Reblock","Treat the error as benign/no-op if the eval already completed — no reblock is needed","Refresh the eval ID from the scheduler rather than reusing a cached one"],"exampleFix":"// before\ne.srv.blockedEvals.Reblock(eval, args.EvalToken)\n// after\nif eval.Status == structs.EvalStatusBlocked {\n    e.srv.blockedEvals.Reblock(eval, args.EvalToken)\n}","handlingStrategy":"validation","validationCode":"eval, _, err := client.Evaluations().Get(evalID)\nif err != nil { return err }\nif eval.Status != \"blocked\" { return fmt.Errorf(\"eval %s is %s, not blocked\", evalID, eval.Status) }","typeGuard":"func isBlocked(e *api.Evaluation) bool { return e != nil && e.Status == \"blocked\" }","tryCatchPattern":null,"preventionTips":["Always GET the eval and check Status == \"blocked\" before reblocking","Treat reblock failures on terminal evals as no-ops in retry loops","Avoid caching eval IDs across scheduling ticks"],"tags":["nomad","rpc","scheduler","state-check"],"backgroundTag":"invalid-state-transition","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"}