docker/cli · error

test and disable can't be set at the same time

Error message

test and disable can't be set at the same time

What it means

Returned by convertHealthcheck (compose/convert/service.go:441-444) when a Compose service's healthcheck sets both 'disable: true' AND a non-empty 'test' list. These are mutually exclusive: disable:true means 'no healthcheck', while test: defines one. When disabled, the converter emits a synthetic 'NONE' test and cannot also honor a user-supplied test.

Solutions

  1. Decide intent: either remove 'disable: true' (to keep the test) or remove 'test:' (to disable).
  2. If overriding a base file, set only one of disable/test in the override.
  3. After editing, run 'docker compose config' to validate conversion before 'up'.

Example fix

# before
services:
  web:
    healthcheck:
      disable: true
      test: ["CMD", "curl", "-f", "http://localhost"]

# after (keep the test, drop disable)
services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
Defensive patterns

Strategy: validation

Validate before calling

// Validate a Compose healthcheck block before conversion.
func validateHealthcheck(hc *composetypes.HealthCheckConfig) error {
    if hc == nil {
        return nil
    }
    if hc.Disable && len(hc.Test) != 0 {
        return errors.New("healthcheck: 'disable' and 'test' are mutually exclusive")
    }
    return nil
}

Type guard

// healthcheckIsSelfConsistent reports whether disable/test are not both set.
func healthcheckIsSelfConsistent(hc *composetypes.HealthCheckConfig) bool {
    if hc == nil {
        return true
    }
    return !(hc.Disable && len(hc.Test) != 0)
}

Prevention

When it happens

Trigger: In docker-compose.yml: a service with healthcheck: { disable: true, test: ["CMD", "curl", "-f", "http://localhost"] }. The converter detects both set and aborts during 'docker compose' conversion (config -> engine mount/container spec).

Common situations: Editing a compose file: a developer disables a healthcheck but forgets to remove/comment the inherited test block. Templating tools that merge disable:true onto services that already define test. Overriding a base compose file's healthcheck with disable while the base keeps test.

Related errors


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

Appendix: source

Thrown at cli/compose/convert/service.go:443

		if hostName, ipAddr, ok := strings.Cut(hostIP, ":"); ok {
			// Convert to SwarmKit notation: IP-address hostname(s)
			hosts = append(hosts, ipAddr+" "+hostName)
		}
	}
	return hosts
}

func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container.HealthConfig, error) {
	if healthcheck == nil {
		return nil, nil
	}
	var (
		timeout, interval, startPeriod, startInterval time.Duration
		retries                                       int
	)
	if healthcheck.Disable {
		if len(healthcheck.Test) != 0 {
			return nil, errors.New("test and disable can't be set at the same time")
		}
		return &container.HealthConfig{
			Test: []string{"NONE"},
		}, nil
	}
	if healthcheck.Timeout != nil {
		timeout = time.Duration(*healthcheck.Timeout)
	}
	if healthcheck.Interval != nil {
		interval = time.Duration(*healthcheck.Interval)
	}
	if healthcheck.StartPeriod != nil {
		startPeriod = time.Duration(*healthcheck.StartPeriod)
	}
	if healthcheck.StartInterval != nil {
		startInterval = time.Duration(*healthcheck.StartInterval)
	}
	if healthcheck.Retries != nil {

View on GitHub (pinned to 4f84911bfe)