{"record":{"id":"17412e70a0cd17b5","repo":"hashicorp/nomad","slug":"eval-not-found","errorCode":null,"errorMessage":"eval not found","messagePattern":"eval not found","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/eval_endpoint.go","lineNumber":519,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to lookup state snapshot: %v\", err)\n\t}\n\tws := memdb.NewWatchSet()\n\n\tcount := 0\n\n\t// Iterate the evaluations and ensure they are safe to delete. It is\n\t// possible passed evals are not safe to delete and would make Nomads state\n\t// a little wonky. The nature of the RPC return error, means a single\n\t// unsafe eval ID fails the whole call.\n\tfor _, evalID := range args.EvalIDs {\n\n\t\tevalInfo, err := serverStateSnapshot.EvalByID(ws, evalID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to lookup eval: %v\", err)\n\t\t}\n\t\tif evalInfo == nil {\n\t\t\treturn errors.New(\"eval not found\")\n\t\t}\n\t\tok, err := serverStateSnapshot.EvalIsUserDeleteSafe(ws, evalInfo)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"eval %s is not safe to delete\", evalInfo.ID)\n\t\t}\n\t\tcount++\n\t}\n\n\t// Generate the Raft request object using the reap request object. This\n\t// avoids adding new Raft messages types and follows the existing reap\n\t// flow.\n\traftReq := structs.EvalReapRequest{\n\t\tEvals:         args.EvalIDs,\n\t\tUserInitiated: true,\n\t\tWriteRequest:  args.WriteRequest,","sourceCodeStart":501,"sourceCodeEnd":537,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/eval_endpoint.go#L501-L537","documentation":"During Eval.Delete, each requested eval ID is looked up in a state-store snapshot via EvalByID. If the ID does not exist in the state store, the delete transaction aborts with this error rather than silently skipping the unknown eval.","triggerScenarios":"Deleting an eval by an ID that has already been garbage-collected, purged, or was typo'd; racing job deregistration which removed the eval between listing and deleting.","commonSituations":"Scripting eval cleanup from a cached list while Nomad GC has already removed old evals; re-running a cleanup script twice; deleting evals after restoring state or pruning with job GC.","solutions":["Re-run 'nomad eval list' and delete only IDs currently present","Handle/skip already-deleted IDs: treat 'eval not found' as success in idempotent cleanup scripts","Lower the chance of GC racing cleanup by disabling job_gc/eval GC temporarily during maintenance","Verify the eval ID (UUID) is correct — no typos or truncated IDs"],"exampleFix":"// before (non-idempotent)\nfor id in $(cat old_evals); do nomad eval delete $id; done\n// after (skip GC'd evals)\nfor id in $(nomad eval list -json | jq -r '.[].ID'); do\n  nomad eval delete \"$id\" || true\ndone","handlingStrategy":"validation","validationCode":"// shell: verify the eval still exists before deleting\nnomad eval list -json | jq -e --arg id \"$ID\" 'map(.ID) | index($id)' >/dev/null \\\n  || { echo \"eval $ID already gone\"; exit 0; }","typeGuard":null,"tryCatchPattern":"// shell: idempotent delete\nnomad eval delete \"$ID\" 2>/dev/null \\\n  || echo \"eval $ID not found — treating as already deleted\"","preventionTips":["Refresh eval lists immediately before deletion (avoid stale caches)","Write cleanup scripts idempotently so 'not found' is a success","Be aware of job/eval GC racing your maintenance scripts","Validate UUIDs to catch typos/truncation"],"tags":["nomad","eval","state-store","not-found"],"backgroundTag":"resource-not-found","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"}