docker/cli · error

invalid type %T for ulimits

Error message

invalid type %T for ulimits

What it means

Thrown by transformUlimits during schema transformation of a service's `ulimits` mapping. Each ulimit value must be either a bare integer (shorthand where soft==hard) or a map with `soft` and `hard` integer keys. Any other YAML scalar/sequence (quoted string, list, bool, null) hits the default branch and is rejected.

Solutions

  1. Use a bare integer: `ulimits: { nproc: 65535 }`.
  2. Or use the explicit map form: `ulimits: { nproc: { soft: 65535, hard: 65535 } }`.
  3. Remove any quotes around the numeric value.

Example fix

# before
services:
  web:
    ulimits:
      nproc: "65535"
# after
services:
  web:
    ulimits:
      nproc: 65535
Defensive patterns

Strategy: validation

Validate before calling

// validate service.ulimits before Transform()
func validateUlimits(svc map[string]any) error {
    u, ok := svc["ulimits"]
    if !ok {
        return nil
    }
    m, ok := u.(map[string]any)
    if !ok {
        return fmt.Errorf("ulimits must be a mapping")
    }
    for name, v := range m {
        switch t := v.(type) {
        case int:
            // ok
        case map[string]any:
            if _, ok := t["soft"].(int); !ok {
                return fmt.Errorf("ulimits.%s.soft must be int", name)
            }
            if _, ok := t["hard"].(int); !ok {
                return fmt.Errorf("ulimits.%s.hard must be int", name)
            }
        default:
            return fmt.Errorf("ulimits.%s: invalid type %T", name, v)
        }
    }
    return nil
}

Type guard

func isUlimitValue(v any) bool {
    switch v.(type) {
    case int:
        return true
    case map[string]any:
        _, softOk := v.(map[string]any)["soft"].(int)
        _, hardOk := v.(map[string]any)["hard"].(int)
        return softOk && hardOk
    }
    return false
}

Prevention

When it happens

Trigger: A service defines `ulimits:` where an entry value is not int or map — e.g. `ulimits: nproc: "65535"` (quoted), `nproc: [65535]` (list), or `nproc: ~`. The transformer is invoked by Transform() for every key under service.ulimits.

Common situations: Quoting the number in YAML, copying an example whose indentation turns the map into a string, or tooling that emits ulimits as strings.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/c8d86c5326d5b563. Report an issue: GitHub.

Appendix: source

Thrown at cli/compose/loader/loader.go:535

			logrus.Warn("cannot expand '~', because the environment lacks HOME")
			return srcPath
		}
		return strings.Replace(srcPath, "~", home, 1)
	}
	return srcPath
}

func transformUlimits(data any) (any, error) {
	switch value := data.(type) {
	case int:
		return types.UlimitsConfig{Single: value}, nil
	case map[string]any:
		ulimit := types.UlimitsConfig{}
		ulimit.Soft = value["soft"].(int)
		ulimit.Hard = value["hard"].(int)
		return ulimit, nil
	default:
		return data, fmt.Errorf("invalid type %T for ulimits", value)
	}
}

// LoadNetworks produces a NetworkConfig map from a compose file Dict
// the source Dict is not validated if directly used. Use Load() to enable validation
func LoadNetworks(source map[string]any, version string) (map[string]types.NetworkConfig, error) {
	networks := make(map[string]types.NetworkConfig)
	err := Transform(source, &networks)
	if err != nil {
		return networks, err
	}
	for name, nw := range networks {
		if !nw.External.External {
			continue
		}
		switch {
		case nw.External.Name != "":
			if nw.Name != "" {

View on GitHub (pinned to 4f84911bfe)