hashicorp/nomad · error
Malformed hard ulimit %v: %v
Error message
Malformed hard ulimit %v: %v
What it means
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.
Source
Thrown at drivers/docker/driver.go:2139
if len(ulimitRaw) == 0 {
return []*containerapi.Ulimit{}, fmt.Errorf("Malformed ulimit specification %v: %q, cannot be empty", name, ulimitRaw)
}
// hard limit is optional
if !strings.Contains(ulimitRaw, ":") {
ulimitRaw = ulimitRaw + ":" + ulimitRaw
}
splitted := strings.SplitN(ulimitRaw, ":", 2)
if len(splitted) < 2 {
return []*containerapi.Ulimit{}, fmt.Errorf("Malformed ulimit specification %v: %v", name, ulimitRaw)
}
soft, err := strconv.Atoi(splitted[0])
if err != nil {
return []*containerapi.Ulimit{}, fmt.Errorf("Malformed soft ulimit %v: %v", name, ulimitRaw)
}
hard, err := strconv.Atoi(splitted[1])
if err != nil {
return []*containerapi.Ulimit{}, fmt.Errorf("Malformed hard ulimit %v: %v", name, ulimitRaw)
}
ulimit := &containerapi.Ulimit{
Name: name,
Soft: int64(soft),
Hard: int64(hard),
}
ulimits = append(ulimits, ulimit)
}
return ulimits, nil
}
func isDockerTransientError(err error) bool {
if err == nil {
return false
}
errMsg := err.Error()View on GitHub (pinned to 482b49bf1a)
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.
Example fix
// before ulimit = "nofile=1024:unlimited" // after ulimit = "nofile=1024:2048"
Defensive patterns
Strategy: validation
Validate before calling
func validUlimit(raw string) bool {
parts := strings.SplitN(raw, ":", 2)
if len(parts) != 2 {
return false
}
_, errS := strconv.Atoi(parts[0])
_, errH := strconv.Atoi(parts[1])
return errS == nil && errH == nil
}
// run validUlimit over every ulimit entry before submitting the job Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- error parsing: root should be an object
- error parsing 'vault': %w
- error parsing 'consul': %w
- error parsing 'keyring': %w
- %s can't parse time duration %s
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/cf09b47d269e7d62.
Report an issue: GitHub.