hashicorp/nomad · error
evals field must not be set
Error message
evals field must not be set
What it means
Nomad's UpdateAlloc RPC rejects client-submitted evaluations. Evals are generated server-side inside the endpoint before the Raft update, so a request carrying args.Evals is treated as invalid/malicious input and rejected. This protects the internal scheduler workflow from clients fabricating evaluations.
Source
Thrown at nomad/node_endpoint.go:1556
return fmt.Errorf("failed to retrieve node %s: %v", targetNodeID, err)
}
if node == nil {
return fmt.Errorf("node %s not found", targetNodeID)
}
if !aclObj.AllowClientOp(node.NodePool) {
return structs.ErrPermissionDenied
}
if err := auth.AuthorizeSameNode(args.GetIdentity(), targetNodeID); err != nil {
return err
}
if node.UnresponsiveStatus() {
return fmt.Errorf("node %s is not allowed to update allocs while in status %s", targetNodeID, node.Status)
}
// Ensure that evals aren't set from client RPCs
// We create them here before the raft update
if len(args.Evals) != 0 {
return fmt.Errorf("evals field must not be set")
}
// Update modified timestamp for client initiated allocation updates
now := time.Now()
var evals []*structs.Evaluation
for _, allocToUpdate := range args.Alloc {
evalTriggerBy := ""
allocToUpdate.ModifyTime = now.UTC().UnixNano()
alloc, _ := n.srv.State().AllocByID(nil, allocToUpdate.ID)
if alloc == nil {
continue
}
if !allocToUpdate.TerminalStatus() && alloc.ClientStatus != structs.AllocClientStatusUnknown {
continue
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Clear the Evals field on the NodeUpdateAllocRequest before sending it (args.Evals = nil)
- Only populate the allowed fields (Allocation fields like TaskStates/DesiredStatus) and construct the request with a fresh structs.NodeUpdateAllocRequest
- If you need to create an eval as a user, use the Eval endpoints or the Nomad API /v1/evaluations, not UpdateAlloc
- Check your client code for copying of a structs.Allocation into args and strip internal-only fields
Example fix
// before
args := structs.NodeUpdateAllocRequest{Eval: myEval, Evals: evals, Alloc: alloc}
// after
args := structs.NodeUpdateAllocRequest{Alloc: alloc} // evals are created by the server Defensive patterns
Strategy: validation
Validate before calling
if len(req.Evals) != 0 {
return fmt.Errorf("client must not set Evals on NodeUpdateAllocRequest")
}
// or proactively: req.Evals = nil before sending Type guard
func evalsUnset(req *structs.NodeUpdateAllocRequest) bool { return len(req.Evals) == 0 } Prevention
- Construct NodeUpdateAllocRequest fresh instead of copying internal structs
- Never populate server-owned fields (Evals, Eval) in client RPCs
- Review custom clients against the current structs.NodeUpdateAllocRequest definition after upgrades
- Use the eval API for eval creation rather than UpdateAlloc
When it happens
Trigger: A Nomad client (node agent) sends a Node.UpdateAlloc RPC with the Evals field populated; only CreateEval, MigrateToken, Preempted fields are accepted from clients.
Common situations: Custom or patched Nomad clients (e.g. third-party schedulers, forked drivers, or integration tooling) that copy a full Allocation struct into the update request instead of zeroing Evals; version drift where a newer client sets Evals.
Related errors
- Must provide the NodeID
- Parameter for choose must be in form '<number>|<key>'
- missing node for client registration
- missing node ID for client registration
- missing datacenter for client registration
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/445e26934d12a2e9.
Report an issue: GitHub.