# Container marked unhealthy but service works

> A container reports unhealthy while it serves traffic fine — a health-probe false negative.

## Symptom

A container — typically the frontend — shows unhealthy in `docker ps`, yet the application is reachable and serving normally in the browser. The health probe logs a "connection refused" even though the service is up.

The cause: the probe targets `localhost`, which resolves to **both** IPv6 (`::1`) and IPv4 (`127.0.0.1`). The probe tool tries IPv6 first, but the server inside the container listens on IPv4 only — so the IPv6 attempt is refused and the probe wrongly reports the container down.

## Confirm

Check the container's reported health versus its real reachability:

```bash
docker ps --format '{{.Names}}\t{{.Status}}' | grep aiboard
```

If a container reads `(unhealthy)` but the app responds when you hit it directly on IPv4, it is this false negative:

```bash
# from inside the container — IPv4 explicitly
docker compose -f docker-compose.release.yml exec frontend \
  sh -c 'wget -qO- http://127.0.0.1:8080/ >/dev/null && echo "IPv4 OK"'
```

If `IPv4 OK` prints, the service is healthy and only the probe was wrong.

## Fix

Current images already probe IPv4 explicitly, so a healthy box should not hit this. If you do see it on an older image:

1. **Confirm the service is actually serving** (the IPv4 check above prints `IPv4 OK`). If it does, no application action is needed — the container is healthy.

2. **Update to a current release image**, where the health probe targets `127.0.0.1` directly and the false negative is gone:

   ```bash
   docker compose -f docker-compose.release.yml up -d
   ```

3. **Re-check** the status clears:

   ```bash
   docker ps --format '{{.Names}}\t{{.Status}}' | grep aiboard
   ```

Because the probe is what was wrong (not the service), a dependent container waiting on
this one's health can be held back even though everything is actually serving. Fix the
probe rather than disabling the healthcheck.

## Prevent

- **Probe the address the server actually binds.** Health probes should target `127.0.0.1` explicitly when the server listens on IPv4 only, so name resolution can't send the probe to an unbound IPv6 address.
- **Distinguish probe failures from service failures.** Before reacting to an `unhealthy` status, confirm with a direct IPv4 request. A green app behind a red probe is a probe bug, not an outage.

## Related

- [Observability & Alerts](/operate/monitoring/) — interpreting health and status signals.
