How to fix ERROR: Service 'web' has an invalid healthcheck definition in Docker
This error occurs when the healthcheck configuration in your docker-compose.yml file contains syntax errors, unsupported options, or conflicting settings. Docker Compose validates healthcheck definitions and rejects configurations that don't conform to the expected format or contain incompatible option combinations.
Quick fix
Fixes ERROR: Service 'web' has an invalid healthcheck definition
# Docker Compose V2
docker compose config
# Docker Compose V1 (legacy)
docker-compose config- Identify the exact validation error
- Fix 'disable: true' conflicts
- Correct the test command format
- Use valid duration formats
# Docker Compose V2docker compose config# Docker Compose V1 (legacy)docker-compose configERROR: Service 'web' has an invalid healthcheck definition
What this error means
The "Service has an invalid healthcheck definition" error indicates that Docker Compose found a problem with how you've configured the healthcheck for a service in your compose file. Healthchecks define commands that Docker runs periodically to determine if a container is functioning properly. Docker Compose performs strict validation on healthcheck configurations before starting any containers. This validation ensures that all required fields are present, values are in the correct format, and no conflicting options are specified together. When validation fails, Compose stops immediately with this error rather than attempting to start containers with invalid configurations. Common validation failures include using the wrong format for the `test` command (mixing string and array formats incorrectly), combining `disable: true` with other healthcheck options, using invalid duration formats for timing parameters, or specifying options that don't exist or are misspelled.
Typical symptoms
- Running 'docker compose up' or 'docker-compose up' immediately fails with 'invalid healthcheck definition'
- The error message references a specific service name that has the problematic healthcheck
- No containers are started - Compose fails during config validation
- The same compose file worked before upgrading Docker Compose versions
- Healthcheck works when defined in Dockerfile but fails in compose file
- Error mentions specific invalid fields like 'disable cannot be combined with other options'
Common causes
- Using 'disable: true' together with other healthcheck options like test, interval, or timeout
- Incorrect test command format - missing CMD, CMD-SHELL prefix in array format
- Invalid duration format for interval, timeout, start_period, or start_interval (must be like '30s', '1m')
- Using healthcheck option in an older compose file version that doesn't support it (requires version 2.1+)
- Misspelled option names (e.g., 'retries' vs 'retry', 'test' vs 'cmd')
- Invalid interpolation in healthcheck test string when using shell variables with special characters
- Using unsupported options like 'start_interval' in older Docker Engine versions (requires 25.0+)
- YAML indentation errors causing options to be parsed incorrectly
How to fix "ERROR: Service 'web' has an invalid healthcheck definition"
Run docker compose config to see the specific validation error:
# Docker Compose V2
docker compose config
# Docker Compose V1 (legacy)
docker-compose configThis will show you the exact issue with your compose file. Common error messages include:
- "disable: true" cannot be combined with other options
- Unsupported config option for healthcheck: 'xxx'
- Invalid interpolation format
- healthcheck.test must be a string or list
Look at the error message to understand which specific option is causing the problem.
When disabling a healthcheck (often to override an image's default), you cannot combine disable: true with any other options:
# WRONG - disable cannot be combined with other options
services:
web:
image: nginx
healthcheck:
disable: true
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
# CORRECT - disable alone
services:
web:
image: nginx
healthcheck:
disable: true
# ALTERNATIVE - use test: ["NONE"] instead of disable
services:
web:
image: nginx
healthcheck:
test: ["NONE"]If you want to override a healthcheck from a parent compose file or image, use the test: ["NONE"] format instead of disable: true, which allows you to include other options if needed.
The healthcheck test command has specific format requirements:
services:
web:
image: nginx
healthcheck:
# Option 1: String format (runs via /bin/sh -c)
test: curl -f http://localhost/ || exit 1
# Option 2: CMD-SHELL array (explicit shell execution)
test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"]
# Option 3: CMD array (direct execution, no shell)
test: ["CMD", "curl", "-f", "http://localhost/"]
# Option 4: Disable healthcheck
test: ["NONE"]Common mistakes to avoid:
# WRONG - Array without CMD or CMD-SHELL prefix
test: ["curl", "-f", "http://localhost/"]
# WRONG - CMD as a string in the command
test: "CMD curl -f http://localhost/"
# WRONG - Missing failure handling in shell format
test: ["CMD-SHELL", "curl http://localhost/"] # Should have || exit 1
# CORRECT
test: ["CMD", "curl", "-f", "http://localhost/"]Duration values must follow Go's duration format:
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
# Valid duration formats
interval: 30s # 30 seconds
timeout: 10s # 10 seconds
retries: 3 # integer, not a duration
start_period: 1m30s # 1 minute 30 seconds
start_interval: 5s # 5 seconds (Docker 25.0+)Valid duration suffixes:
- s - seconds (e.g., 30s)
- m - minutes (e.g., 5m)
- h - hours (e.g., 1h)
- Combined: 1h30m, 1m30s
Invalid formats:
# WRONG - Missing unit
interval: 30
# WRONG - Invalid unit
timeout: 10sec
# WRONG - Quoted numbers
retries: "3"
# CORRECT
interval: 30s
timeout: 10s
retries: 3The healthcheck option requires compose file version 2.1 or higher:
# For Docker Compose V1 (legacy)
version: "2.1" # Minimum for healthcheck
# or
version: "3" # Also supports healthcheck
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]For Docker Compose V2 (modern), the version field is optional but if present should not be "1" or "2.0":
# Docker Compose V2 - version is optional
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]Check your Docker Compose version:
# Docker Compose V2
docker compose version
# Docker Compose V1 (legacy)
docker-compose versionNote: The start_interval option requires Docker Engine 25.0 or later. If you see an error about this option, either upgrade Docker or remove it.
When using shell variables in healthcheck tests, special characters can cause interpolation errors:
# WRONG - $? causes interpolation error
services:
web:
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/ && echo $?"]
# CORRECT - Escape the dollar sign
services:
web:
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/ && echo $$?"]
# BETTER - Use explicit exit
services:
web:
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"]For environment variables in healthchecks:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: myuser
healthcheck:
# Use shell variable syntax carefully
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
# Or use the direct value
test: ["CMD-SHELL", "pg_isready -U myuser"]YAML indentation errors can cause healthcheck options to be parsed incorrectly:
# WRONG - Inconsistent indentation
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s # This is at wrong level - not part of healthcheck!
# CORRECT - All options indented under healthcheck
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40sUse a YAML linter to check your file:
# Using yamllint
yamllint docker-compose.yml
# Or validate with docker compose
docker compose config --quiet && echo "Valid" || echo "Invalid"Also ensure you're using spaces, not tabs, for indentation in YAML files.
Advanced notes
Healthcheck inheritance and overrides: When extending services or using multiple compose files, healthcheck definitions can conflict. A child service cannot partially override a parent's healthcheck - it must completely replace it or disable it:
# base.yml
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
# override.yml - This completely replaces the healthcheck
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 60s
timeout: 20sCompose Specification vs legacy versions: The modern Compose Specification (used by Docker Compose V2) merges the features of versions 2.x and 3.x. Some options that were version-specific are now universally available. If migrating from an older compose file, you may encounter validation differences.
Image healthchecks vs compose healthchecks: If your image has a HEALTHCHECK instruction in its Dockerfile, the compose file healthcheck will override it. To inherit the image's healthcheck, omit the healthcheck section entirely. To disable it, use disable: true or test: ["NONE"].
Debugging with --dry-run: Test your compose configuration without starting containers:
docker compose up --dry-runThis validates the entire configuration including healthchecks and shows what would happen.
Schema validation: You can validate your compose file against the official JSON schema:
# Using check-jsonschema
pip install check-jsonschema
check-jsonschema --schemafile https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json docker-compose.ymlFrequently asked questions
- What does "ERROR: Service 'web' has an invalid healthcheck definition" mean?
- The "Service has an invalid healthcheck definition" error indicates that Docker Compose found a problem with how you've configured the healthcheck for a service in your compose file. Healthchecks define commands that Docker runs periodically to determine if a container is functioning properly. Docker Compose performs strict validation on healthcheck configurations before starting any containers.
- How do I fix "ERROR: Service 'web' has an invalid healthcheck definition"?
- This error occurs when the healthcheck configuration in your docker-compose.yml file contains syntax errors, unsupported options, or conflicting settings. Docker Compose validates healthcheck definitions and rejects configurations that don't conform to the expected format or contain incompatible option combinations.
- What causes "ERROR: Service 'web' has an invalid healthcheck definition"?
- Using 'disable: true' together with other healthcheck options like test, interval, or timeout Incorrect test command format - missing CMD, CMD-SHELL prefix in array format Invalid duration format for interval, timeout, start_period, or start_interval (must be like '30s', '1m')
- Is the "ERROR: Service 'web' has an invalid healthcheck definition" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐Docker Official Documentation
- ๐Define services in Docker Compose - Docker Docs(Official Docs)
- ๐Control startup order - Docker Docs(Official Docs)
- ๐ฌUnsupported config option: 'healthcheck' - Stack Overflow(Stack Overflow)
- ๐
- ๐
- ๐ฌDocker Compose healthcheck options - Stack Overflow(Stack Overflow)