{"record":{"id":"28e85776264a87a4","repo":"hashicorp/nomad","slug":"plan-exceeds-max-allocation","errorCode":null,"errorMessage":"plan exceeds max allocation","messagePattern":"plan exceeds max allocation","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/funcs.go","lineNumber":147,"sourceCode":"\n\tif _, exists := a[nodeID][name]; !exists {\n\t\treturn nil, false\n\t}\n\n\treturn a[nodeID][name], true\n}\n\n// AllocsFit checks if a given set of allocations will fit on a node.\n// The netIdx can optionally be provided if its already been computed.\n// If the netIdx is provided, it is assumed that the client has already\n// ensured there are no collisions. If checkDevices is set to true, we check if\n// there is a device oversubscription.\nfunc AllocsFit(node *Node, allocs []*Allocation, netIdx *NetworkIndex, checkDevices bool) (bool, string, *ComparableResources, error) {\n\t// Compute the allocs' utilization from zero\n\tused := new(ComparableResources)\n\tif node.NodeMaxAllocs != 0 {\n\t\tif node.NodeMaxAllocs < len(allocs) {\n\t\t\treturn false, \"max allocation exceeded\", used, fmt.Errorf(\"plan exceeds max allocation\")\n\t\t}\n\t}\n\treservedCores := map[uint16]struct{}{}\n\tvar coreOverlap bool\n\n\thostVolumeClaims := map[string]int{}\n\texclusiveHostVolumeClaims := []string{}\n\n\t// For each alloc, add the resources\n\tfor _, alloc := range allocs {\n\t\t// Do not consider the resource impact of terminal allocations\n\t\tif alloc.ClientTerminalStatus() {\n\t\t\tcontinue\n\t\t}\n\n\t\tcr := alloc.AllocatedResources.Comparable()\n\t\tused.Add(cr)\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/funcs.go#L129-L165","documentation":"AllocsFit returns this error when the number of allocations in the proposed plan exceeds the node's NodeMaxAllocs limit. Nomad enforces a per-node cap on total allocations so a node never schedules more placements than it can support, regardless of free resources.","triggerScenarios":"Scheduler evaluation calls AllocsFit(node, allocs, netIdx, checkDevices) and len(allocs) > node.NodeMaxAllocs (with NodeMaxAllocs != 0); triggered during plan applier or test-fitting when packing many small tasks onto one node.","commonSituations":"Clusters running many tiny jobs (e.g. hundreds of one-task system/batch jobs) hitting the per-node allocation ceiling; nodes with high NodeMaxAllocs removed or default changed between Nomad versions causing 'max allocation exceeded' plan rejections.","solutions":["Reduce the number of allocations targeting that node (consolidate tasks, scale down replicas)","Spread the workload across more client nodes by adding capacity or adjusting constraints","Increase node.NodeMaxAllocs via the client config (client { max_allocs = N }) if hardware genuinely supports more","Inspect placement failures in 'nomad job status' output to confirm the max-allocs cause"],"exampleFix":"// before (client config)\nclient {\n}\n// after\nclient {\n  max_allocs = 200\n}","handlingStrategy":"validation","validationCode":"// go: pre-check proposed placement count against the node cap\nif node.NodeMaxAllocs != 0 && currentAllocs+newAllocs > node.NodeMaxAllocs {\n    return fmt.Errorf(\"node %s would exceed max_allocs (%d)\", node.ID, node.NodeMaxAllocs)\n}","typeGuard":null,"tryCatchPattern":"fits, reason, used, err := structs.AllocsFit(node, allocs, netIdx, true)\nif err != nil || !fits {\n    log.Printf(\"placement rejected: %s (used %+v)\", reason, used)\n}","preventionTips":["Keep task granularity coarse enough that per-node alloc counts stay well below max_allocs","Add jobs across multiple nodes instead of packing one node","Set client max_allocs consciously relative to hardware"],"tags":["nomad","scheduler","capacity","plan"],"backgroundTag":"node-capacity-exceeded","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"}