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

  1. Set the hard ulimit to a plain integer, e.g. 'nofile=1024:2048' instead of 'nofile=1024:unlimited'.
  2. If the hard value should equal the soft value, repeat it explicitly: 'nofile=1024:1024'.
  3. Remove unit suffixes and whitespace; use raw numbers (2048 not 2k).
  4. 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

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

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/cf09b47d269e7d62. Report an issue: GitHub.