Docker "device or resource busy" - Fix Unmount/Remove Failures in CI
Docker could not remove a container, volume, or path because the kernel says it is still in use. Something still has the mount or a file open, so the unlink/unmount is refused.
What this error means
A docker rm, docker volume rm, or container shutdown fails with device or resource busy (often unlinkat /var/lib/docker/...: device or resource busy). The resource lingers and can block re-creating it on the next run.
Error response from daemon: driver "overlay2" failed to remove root filesystem
for a1b2c3...: unlinkat /var/lib/docker/overlay2/.../merged: device or resource busyCommon causes
A mount inside the container is still active
A volume or bind mount that did not unmount cleanly keeps the container’s filesystem busy, so its root cannot be removed.
Another process holds an open file/handle
A leaked process, a still-attached docker exec session, or a host process with an open file under the container’s graph dir keeps it busy.
Leftover state on a reused runner
On a long-lived runner, a prior job left a half-cleaned container/volume whose mounts are still referenced.
How to fix it
Force-remove and prune leftover state
Stop and force-remove the container, then prune dangling volumes.
docker rm -f <container> 2>/dev/null || true
docker volume rm -f <volume> 2>/dev/null || true
docker system prune -fFind and release what holds the mount
- Ensure no
docker execsession is still attached to the container. - Check for host processes with open files under the container path and stop them.
- As a last resort on an ephemeral runner, restart the Docker daemon to release stale mounts.
How to prevent it
- Use
--rmfor ephemeral containers so they unmount and self-clean on exit. - Close exec sessions and stop child processes before removing containers.
- Add a cleanup/prune step on long-lived runners between jobs.