The job gave up waiting for a dependency (database, queue, app container) to pass its healthcheck. Service-not-ready is a mechanical, transient condition: the service often just needs a moment longer.
What this error means
A wait/healthcheck step fails with timed out waiting for ... or a connection refused on a service port. A re-run usually passes once the service starts in time.
shell
wait-for-it.sh: timeout occurred after waiting 30 seconds for postgres:5432
##[error] Service container 'db' failed to become healthy.
Common causes
The service started slower than the wait allowed
A database or app container can take longer than the fixed wait on a cold or busy runner.
A too-short or missing readiness wait
Connecting before the service is ready (or with too short a timeout) fails intermittently.
How to fix it
Wait for actual readiness with a generous timeout
Poll the real health endpoint/port instead of a fixed sleep.
shell
for i in $(seq 1 60); do
pg_isready -h localhost -p 5432 && break
sleep 2
done
Use built-in healthchecks
Define a service health-cmd/healthcheck so CI waits on real readiness.
Increase the readiness timeout for slow-starting services.
Start the service early so it is warm by the time tests run.
How to prevent it
Poll readiness, never a fixed sleep.
Give slow services a generous readiness window.
Service-not-ready is mechanical and transient: managed runners detect it, automatically retry, and offer warm capacity so the dependency is more likely ready, so a one-off blip does not fail the build.
Frequently asked questions
What causes "Healthcheck timed out"?
A database or app container can take longer than the fixed wait on a cold or busy runner.
How do I fix Healthcheck timed out?
Poll the real health endpoint/port instead of a fixed sleep.
Can Latchkey fix this automatically?
Yes. Latchkey runs your GitHub Actions on managed runners that detect this failure, apply the fix, and retry the job automatically - self-healing is on by default.