docker compose up -d --force-recreate --no-build app
Root cause. The container object survived a rebuild with HostConfig.NetworkMode=asce_default but no network sandbox (NetworkSettings.Networks = {}). No sandbox ⇒ no veth, no netns, and no Docker embedded DNS at <ip-address>; the process's /etc/resolv.conf falls back to external resolvers (lookup postgres on <ip-address>:53: network unreachable. Siblings are healthy because their sandboxes exist. The DNS error naming an external resolver IP (not
Confirm in two commands:
docker inspect -f '{{json .NetworkSettings.Networks}}' <container> # -> {}
docker inspect -f '{{.HostConfig.NetworkMode}}' <container> # -> asce_default
The fix (the entire point: up --no-build alone restarts the same broken container object, so no sandbox is ever allocated):
docker compose up -d --force-recreate --no-build
# targeted variant (zero impact on healthy siblings):
docker compose up -d --force-recreate --no-build app
--force-recreate discards the broken container and allocates a fresh sandbox + veth + embedded DNS; --no-build reuses current images (the bug is in the container, not the image).
Verify:
docker compose ps
docker inspect -f '{{.Name}} networks={{len .NetworkSettings.Networks}} health={{if .State.Health}}{{.State.Health.Status}}{{end}}' $(docker compose ps -q)
docker compose exec -T app getent hosts postgres # must resolve via <ip-address>
Deliverable repo ~/asce-fix/ (compose repro with DNS-based healthchecks, diagnose.sh, fix.sh, verify.sh, README.md, and a 23-test harness):
./diagnose.sh # flags containers with Networks={} but NetworkMode=<project>_<net>
./fix.sh # docker compose up -d --force-recreate --no-build && ./verify.sh
./verify.sh # sandbox populated + healthcheck green + in-container DNS
The daemon itself cannot run in this sandbox (dockerd needs root; rootless is blocked by `apparmor_restrict_unprivileged_userns=1` + no-new-privileges), so I verified with a **mocked daemon that encodes the exact reported behavior**, plus the real daemonless compose client. `~/asce-fix/tests/run_tests.py` — **23/23 passing**: - **T1** healthy fleet → `diagnose`/`verify` exit 0, `fix` is a no-op, no recreation issued - **T2** broken `app` → `diagnose` exits 1 and names the container + `asce_default` - **T3** the trap: `compose up -d --no-build` exits 0 but state stays broken (nets=0, unhealthy) — proves it restarts the *same* container with no new sandbox - **T4** `fix.sh` issues exactly `compose up -d --force-recreate --no-build`; afterwards sandbox populated (nets 0→1), healthcheck green, healthy sibling untouched - **T5** `verify.sh` exits 0 post-fix and reports `DNS OK: app resolves 'postgres'` - **T6** edge cases: `host`/`none`/`bridge` containers with 0 networks are *not* misflagged as broken; only compose-managed (`<project>_<net>`) modes are - **T7** real `docker compose config -q` validates the YAML daemonlessly; rendered config contains `asce_default` Also confirmed the flags exist on this client (`docker compose up --help` → `--force-recreate`, `--no-build`) and the DNS-failure signature (external resolver IP) is consistent with a missing sandbox. **Edge cases tested:** healthy fleet (no-op), plain `--no-build` restart (no fix), targeted vs full recreate, host/none-network_mode containers (false-positive avoidance), empty project, daemonless compose validation.
{"model": "deepseek-v4-flash", "problem_class": "docker-container-missing-network-sandbox", "result": "passed", "tests": 23}Root cause. The container object survived a rebuild with HostConfig.NetworkMode=asce_default but no network sandbox (NetworkSettings.Networks = {}). No sandbox ⇒ no veth, no netns, and no Docker embedded DNS at <ip-address>; the process's /etc/resolv.conf falls back to external resolvers (lookup postgres on <ip-address>:53: network unreachable. Siblings are healthy because their sandboxes exist. The DNS error naming an external resolver IP (not
Confirm in two commands:
docker inspect -f '{{json .NetworkSettings.Networks}}' <container> # -> {}
docker inspect -f '{{.HostConfig.NetworkMode}}' <container> # -> asce_default
The fix (the entire point: up --no-build alone restarts the same broken container object, so no sandbox is ever allocated):
docker compose up -d --force-recreate --no-build
# targeted variant (zero impact on healthy siblings):
docker compose up -d --force-recreate --no-build app
--force-recreate discards the broken container and allocates a fresh sandbox + veth + embedded DNS; --no-build reuses current images (the bug is in the container, not the image).
Verify:
docker compose ps
docker inspect -f '{{.Name}} networks={{len .NetworkSettings.Networks}} health={{if .State.Health}}{{.State.Health.Status}}{{end}}' $(docker compose ps -q)
docker compose exec -T app getent hosts postgres # must resolve via <ip-address>
Deliverable repo ~/asce-fix/ (compose repro with DNS-based healthchecks, diagnose.sh, fix.sh, verify.sh, README.md, and a 23-test harness):
./diagnose.sh # flags containers with Networks={} but NetworkMode=<project>_<net>
./fix.sh # docker compose up -d --force-recreate --no-build && ./verify.sh
./verify.sh # sandbox populated + healthcheck green + in-container DNS
The daemon itself cannot run in this sandbox (dockerd needs root; rootless is blocked by `apparmor_restrict_unprivileged_userns=1` + no-new-privileges), so I verified with a **mocked daemon that encodes the exact reported behavior**, plus the real daemonless compose client. `~/asce-fix/tests/run_tests.py` — **23/23 passing**: - **T1** healthy fleet → `diagnose`/`verify` exit 0, `fix` is a no-op, no recreation issued - **T2** broken `app` → `diagnose` exits 1 and names the container + `asce_default` - **T3** the trap: `compose up -d --no-build` exits 0 but state stays broken (nets=0, unhealthy) — proves it restarts the *same* container with no new sandbox - **T4** `fix.sh` issues exactly `compose up -d --force-recreate --no-build`; afterwards sandbox populated (nets 0→1), healthcheck green, healthy sibling untouched - **T5** `verify.sh` exits 0 post-fix and reports `DNS OK: app resolves 'postgres'` - **T6** edge cases: `host`/`none`/`bridge` containers with 0 networks are *not* misflagged as broken; only compose-managed (`<project>_<net>`) modes are - **T7** real `docker compose config -q` validates the YAML daemonlessly; rendered config contains `asce_default` Also confirmed the flags exist on this client (`docker compose up --help` → `--force-recreate`, `--no-build`) and the DNS-failure signature (external resolver IP) is consistent with a missing sandbox. **Edge cases tested:** healthy fleet (no-op), plain `--no-build` restart (no fix), targeted vs full recreate, host/none-network_mode containers (false-positive avoidance), empty project, daemonless compose validation.
{"model": "deepseek-v4-flash", "problem_class": "docker-container-missing-network-sandbox", "result": "passed", "tests": 23}