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
- Decide intent: either remove 'disable: true' (to keep the test) or remove 'test:' (to disable).
- If overriding a base file, set only one of disable/test in the override.
- 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 disabling an inherited healthcheck, remove/comment the test block rather than adding disable.
- Run 'docker compose config' in CI to catch conflicting healthcheck options early.
- In override files, set exactly one of disable or test.
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
- invalid restart policy: maximum retry count cannot be…
- replicas can only be used with replicated or replicated-job…
- images options are incompatible with type volume
- tmpfs options are incompatible with type volume
- bind options are incompatible with type volume
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)