15.3.2.4 Healthcheck Missing State
A focused guide to Healthcheck Missing State, connecting core concepts with practical Docker and container operations.
The healthcheck missing state refers to a container that has no HEALTHCHECK configured at all, which is distinct from any of the three actual health states (starting, healthy, unhealthy) and represents a meaningful observability gap: there is simply no automated signal available for whether the container is actually capable of functioning correctly, only whether its process is technically running.
Recognizing a container with no health check
A container with no configured health check returns an empty health status object when inspected, rather than any of the three defined states:
docker inspect --format='{{.State.Health}}' my-api
<no value>
docker ps
CONTAINER ID IMAGE STATUS
3f29a8c1d8e2 my-api Up 2 hours
Notice the absence of a parenthetical health indicator in the docker ps output, which appears only for containers that actually have a health check configured; a container missing this entirely is easy to overlook precisely because nothing in the default output draws attention to the absence.
Why this matters
Without a health check, the only available signal about a container's status is whether its process is running at all, which says nothing about whether it can actually serve requests correctly. A container can be "Up" and running for hours while being completely unable to handle real traffic, deadlocked, disconnected from its database, or stuck in some other broken state, with absolutely nothing in Docker's own tooling surfacing this:
docker ps
Up 3 hours
This status line provides no more confidence about the container's actual health than knowing a light switch is in the "on" position tells you the lightbulb itself has not burned out.
Auditing a fleet for missing health checks
For a host or deployment running many containers, identifying which ones lack a configured health check is a useful, quick audit, since it directly highlights services with a meaningful observability gap that the rest of the fleet does not share:
for c in $(docker ps --format "{{.Names}}"); do
health=$(docker inspect --format='{{.State.Health.Status}}' "$c" 2>/dev/null)
if [ -z "$health" ]; then
echo "$c: NO HEALTH CHECK CONFIGURED"
fi
done
Running this kind of audit periodically, or as part of a deployment pipeline's own verification step, catches the case where a new service is deployed without a health check being added, which can otherwise go unnoticed for a long time, since the container appears to be running normally by every other visible indicator.
Inheriting a missing health check from a base image
A health check defined in a Dockerfile is part of the image, and a service built without ever adding a HEALTHCHECK instruction, often because the base image itself does not define one and no one explicitly added one downstream, simply has no health check by default, silently inheriting this gap unless someone deliberately addresses it:
FROM node:20
WORKDIR /app
COPY . .
CMD ["node", "server.js"]
This Dockerfile, lacking any HEALTHCHECK instruction, produces an image whose containers will always show no health status, regardless of how the container is eventually run, unless a health check is supplied externally at run time instead.
Supplying a health check externally at run time
Even if an image itself defines no health check, one can be added when the container is actually started, which is useful for retrofitting health checking onto a third-party image that was not built with one:
docker run -d --health-cmd="curl -f http://localhost:3000/healthz || exit 1" \
--health-interval=15s --health-retries=3 my-api:third-party
services:
api:
image: third-party/some-service:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/healthz"]
interval: 15s
This run-time override takes precedence over whatever the image itself defines (or does not define), making it a practical way to close the gap for an image that cannot easily be rebuilt or modified directly.
Explicitly disabling a health check versus never having one
Docker also supports explicitly disabling an inherited health check using NONE, which is a distinct, deliberate choice from simply never having defined one, and is worth distinguishing when auditing, since a service explicitly opting out is a different situation than one that simply never had the question considered:
HEALTHCHECK NONE
docker run -d --no-healthcheck my-api
A container with an explicitly disabled health check and one that simply never had one configured both show the same empty health status, but understanding which situation applies, a deliberate decision versus an oversight, matters when deciding whether to add one going forward.
Treating missing health checks as a deployment gate
Because the gap a missing health check creates is significant and easy to overlook, some organizations treat the presence of a health check as a mandatory requirement enforced during image review or as part of a deployment pipeline's own validation step, rather than relying on individual engineers to remember to add one for every new service:
docker inspect --format='{{.Config.Healthcheck}}' my-image:latest
if [ -z "$(docker inspect --format='{{.Config.Healthcheck}}' my-image:latest)" ]; then
echo "ERROR: no health check defined in image"
exit 1
fi
A pipeline check like this, failing a build or deployment that lacks a defined health check, converts an easy-to-overlook gap into something that cannot silently slip through unnoticed.
Common mistakes
- Assuming a container showing "Up" in
docker psis necessarily functioning correctly, when this only confirms the process is running, not that it can serve requests. - Not auditing existing services for missing health checks, leaving a fleet-wide observability gap unaddressed simply because no individual service's absence was ever specifically noticed.
- Building images from base images with no health check and never adding one downstream, silently inheriting the gap into every derived service.
- Conflating an explicitly disabled health check (
NONE) with one that was simply never considered, missing the distinction between a deliberate choice and an oversight. - Relying on individual engineer diligence to add health checks consistently, rather than enforcing their presence through an automated pipeline check.
The healthcheck missing state is not really a state in Docker's own model at all, it is the absence of one, and recognizing it requires actively checking for it, since nothing in the default container listing draws attention to a meaningful gap that leaves a container's actual functional health completely unmonitored beyond the bare fact that its process happens to still be running.