{"record":{"id":"cf09b47d269e7d62","repo":"hashicorp/nomad","slug":"malformed-hard-ulimit-v-v","errorCode":null,"errorMessage":"Malformed hard ulimit %v: %v","messagePattern":"Malformed hard ulimit (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/docker/driver.go","lineNumber":2139,"sourceCode":"\t\tif len(ulimitRaw) == 0 {\n\t\t\treturn []*containerapi.Ulimit{}, fmt.Errorf(\"Malformed ulimit specification %v: %q, cannot be empty\", name, ulimitRaw)\n\t\t}\n\t\t// hard limit is optional\n\t\tif !strings.Contains(ulimitRaw, \":\") {\n\t\t\tulimitRaw = ulimitRaw + \":\" + ulimitRaw\n\t\t}\n\n\t\tsplitted := strings.SplitN(ulimitRaw, \":\", 2)\n\t\tif len(splitted) < 2 {\n\t\t\treturn []*containerapi.Ulimit{}, fmt.Errorf(\"Malformed ulimit specification %v: %v\", name, ulimitRaw)\n\t\t}\n\t\tsoft, err := strconv.Atoi(splitted[0])\n\t\tif err != nil {\n\t\t\treturn []*containerapi.Ulimit{}, fmt.Errorf(\"Malformed soft ulimit %v: %v\", name, ulimitRaw)\n\t\t}\n\t\thard, err := strconv.Atoi(splitted[1])\n\t\tif err != nil {\n\t\t\treturn []*containerapi.Ulimit{}, fmt.Errorf(\"Malformed hard ulimit %v: %v\", name, ulimitRaw)\n\t\t}\n\n\t\tulimit := &containerapi.Ulimit{\n\t\t\tName: name,\n\t\t\tSoft: int64(soft),\n\t\t\tHard: int64(hard),\n\t\t}\n\t\tulimits = append(ulimits, ulimit)\n\t}\n\treturn ulimits, nil\n}\n\nfunc isDockerTransientError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\n\terrMsg := err.Error()","sourceCodeStart":2121,"sourceCodeEnd":2157,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/docker/driver.go#L2121-L2157","documentation":"The docker driver parses a Nomad task ulimit value of the form 'soft=hard' (e.g. 'nofile=1024:2048'). This error means the hard-limit half of the ulimit string could not be converted to an integer via strconv.Atoi. The driver aborts parsing and returns no ulimits rather than starting a container with a partial limit config.","triggerScenarios":"Task driver configuration contains a ulimit entry like 'name=soft:hard' where the hard value (the text after the second separator) is not a plain decimal integer, e.g. 'nofile=1024:unlimited', 'memlock=64:' (empty hard part), or 'core=0:2048k' (suffix characters).","commonSituations":"Copy-pasting Linux ulimit semantics where 'unlimited'/'infinity' is valid but not accepted here; adding unit suffixes like 'k'/'m'; leaving the hard value empty because it 'inherits' the soft value in shell ulimit syntax; typos or whitespace in the HCL/job config.","solutions":["Set the hard ulimit to a plain integer, e.g. 'nofile=1024:2048' instead of 'nofile=1024:unlimited'.","If the hard value should equal the soft value, repeat it explicitly: 'nofile=1024:1024'.","Remove unit suffixes and whitespace; use raw numbers (2048 not 2k).","Check the ulimit stanza format in your Nomad job 'resources'/driver config and correct the delimiter-separated pair."],"exampleFix":"// before\nulimit = \"nofile=1024:unlimited\"\n// after\nulimit = \"nofile=1024:2048\"","handlingStrategy":"validation","validationCode":"func validUlimit(raw string) bool {\n    parts := strings.SplitN(raw, \":\", 2)\n    if len(parts) != 2 {\n        return false\n    }\n    _, errS := strconv.Atoi(parts[0])\n    _, errH := strconv.Atoi(parts[1])\n    return errS == nil && errH == nil\n}\n// run validUlimit over every ulimit entry before submitting the job","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Lint ulimit values as 'name=int:int' pairs in CI before job submission.","Never write 'unlimited' or unit suffixes in Nomad ulimit configs.","Keep a shared, tested ulimit snippet for jobs that need raised limits."],"tags":["docker-driver","ulimit","config-parsing"],"backgroundTag":"malformed-numeric-config-value","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"}