Fix: Docker container name already in use
Part of: Docker, DevOps & Infrastructure
Quick Answer
How to fix Docker 'container name already in use by container' error caused by stopped containers, name conflicts, compose restarts, and stale container state.
Docker Refusing to Reuse the Name
Personally, I think this error is one of Docker’s most over-encountered. It is essentially Docker telling you “there is a previous container with this name; I will not silently drop it.” The fix is rarely complicated, but the right command depends on whether you want to keep the old container around for inspection or wipe it. I learned to default to docker rm -f in scripts and docker rename in production. You run docker run or docker-compose up and get:
docker: Error response from daemon: Conflict. The container name "/my-app" is already in use
by container "abc123def456". You have to remove (or rename) that container to be able to reuse
that name.Or from Docker Compose:
Creating my-project_web_1 ... error
ERROR: for web Cannot create container for service web: Conflict.
The container name "/my-project_web_1" is already in useDocker requires unique container names. A container with the specified name already exists, either running or stopped.
Quick Reference Before You Dive In
If you arrived here from Google with a fresh name conflict, the five facts that resolve roughly 90 percent of cases:
docker rm -f my-appremoves a container with that name regardless of state. The-fflag also stops running containers in one command. The Dockerrunreference and thermcommand docs are the canonical sources.docker run --rmauto-removes the container on exit. Use it for dev, testing, and CI; the name slot is freed immediately when the container stops.- Docker 25+ supports
docker run --replace. It atomically stops and removes any existing container with the same name before creating the new one. Cleanest fix for deploy scripts. docker compose downremoves containers AND frees their names.docker compose stopdoes NOT; the nextupfinds the old containers and may conflict.- For CI runners, ALWAYS include a unique suffix in container names.
--name my-app-${{ github.run_id }}for GitHub Actions;--name my-app-${CI_JOB_ID}for GitLab. Parallel jobs on shared runners collide without it.
The rest of this article walks through each cause in detail, plus the failure modes most other guides skip.
Why Docker Holds Onto the Name
Every Docker container has a unique name. When you use --name my-app or Docker Compose assigns a name, Docker checks for existing containers with that name. Stopped containers still occupy the name until they are removed. The Docker daemon treats created, running, paused, restarting, exited, and dead containers all as live entries in the container store; only after docker rm does the name slot free up.
The behavior is deliberate. Container names are user-facing handles; if Docker silently dropped a stopped container to make room for a new one with the same name, you would lose access to the previous container’s logs, exit code, and filesystem layers before you had a chance to inspect them. The downside is that this safety mechanism turns every crash, every CI rerun, and every docker-compose stop/up cycle into a potential name conflict.
Common causes:
- Previous container was stopped but not removed.
docker stopdoes not delete the container. - Crashed container left behind. A container that exited with an error still occupies the name.
- Docker Compose recreate conflict. Compose cannot recreate a container if the old one still exists.
- Multiple terminal sessions. You ran
docker run --name my-apptwice without removing the first. - Script or CI/CD pipeline rerun. A deployment script runs
docker run --nameon each deployment without cleaning up old containers. - Docker daemon restart with persistent containers. Containers with a restart policy come back after the daemon restarts, but the names they reclaim may collide with whatever script you ran during the outage.
- Zombie containers from a different Docker context. Switching contexts (Docker Desktop’s “use other Docker engine” toggle, or
docker context use) can leave you with two daemons that each think they own the name.
Platform and Environment Differences
The same “name already in use” error has different root causes depending on where Docker runs.
Linux native. This is the simplest environment. The Docker daemon (dockerd) runs directly on the host, and /var/lib/docker/containers/ holds the container state. docker rm removes the directory entry, the name frees up, and the next docker run succeeds. If you hit phantom conflicts on Linux, it usually means a previous docker run succeeded just enough to register the name before crashing; docker ps -a --filter "name=^my-app$" will show it as Created rather than Exited.
macOS (Docker Desktop). Docker Desktop runs a Linux VM (HyperKit on Intel, Virtualization.framework on Apple Silicon) and the Docker daemon lives inside that VM. The macOS Docker CLI is a thin client that talks to the VM over a socket. Two things go wrong here. First, restarting Docker Desktop without first stopping containers leaves them in a weird state when the VM restarts; they show as Created but cannot be inspected. Second, the VM occasionally fails to release container names after a forced quit; docker system prune -f from a fresh Docker Desktop session is the reset button. On Apple Silicon specifically, switching between amd64 and arm64 containers can leave the daemon thinking the old container is still valid even though its filesystem layers were rebuilt for a different arch.
Windows (Docker Desktop with WSL2 backend). Same VM-layer model as macOS, but with WSL2 as the VM. Container names live inside the WSL2 distro docker-desktop, not in your user distro. If you run docker run --name my-app from a PowerShell window and then from a WSL2 Ubuntu shell, both commands talk to the same daemon and conflict; they are not separate spaces despite feeling separate. Worse, if WSL2 shuts down (wsl --shutdown or the laptop suspending), containers with restart: always come back automatically on next start, and any script that assumed a clean slate trips the name conflict immediately.
WSL2 with Docker Engine installed inside the distro (not Docker Desktop). This is a different model: each WSL2 distro has its own dockerd and its own container namespace. Names do not collide across distros, but a single distro that has not been shut down cleanly often leaves containers in a restarting loop after WSL2 restarts. docker ps -a plus docker rm -f $(docker ps -aq) resets it.
Rootless Podman (drop-in docker replacement). Podman uses its own socket per user ($XDG_RUNTIME_DIR/podman/podman.sock) and there is no system-wide daemon. Two different users on the same Linux host can each have a container named my-app without conflict, because they are entirely separate stores. The trap is when a system service (systemd user unit) and an interactive shell both reach the same socket and run uncoordinated cleanups. Podman’s --replace flag (podman run --replace) has worked since Podman 3.x and avoids the issue entirely.
Docker Desktop on Linux. A newer offering (since 2022) that, like the macOS and Windows versions, runs the daemon inside a VM via QEMU. Container names live in the VM, separate from any dockerd you may have installed directly on the host. If you switch between Docker Desktop and host-installed Docker via docker context use desktop-linux vs docker context use default, the same name can exist in both, but each docker rm only affects the active context. Symptoms: docker ps -a shows no container named my-app, but docker run --name my-app still fails. Check docker context ls first.
CI runners (GitHub Actions, GitLab, CircleCI). Hosted runners are usually ephemeral, so name conflicts there mean either two parallel jobs on the same self-hosted runner used the same container name, or a previous job’s cleanup step did not run. Always include a unique suffix (the job ID or run number) in container names: --name my-app-${{ github.run_id }} for GitHub Actions, --name my-app-${CI_JOB_ID} for GitLab. Self-hosted runners should also include a cleanup step that runs docker rm -f for the expected name in a post-job or always() block, so a failed previous run does not poison the next one.
When to Use Which Fix
The next eight sections cover the fixes in detail. The table below maps your situation to the recommended fix.
| Your situation | Recommended fix | Why |
|---|---|---|
| Old container is stopped, want it gone | Fix 1: docker rm my-app or docker rm -f | Standard removal |
| One-off command or dev workflow | Fix 2: docker run --rm | Auto-cleanup |
| Compose stack hit a name conflict | Fix 3: docker compose down, then up | Compose handles names |
| Need to run multiple instances | Fix 4: include unique suffix | Names must be unique |
| Deploy script keeps hitting this | Fix 5: stop / rm / run pattern, or --replace | Idempotent deploys |
| Accumulated stopped containers | Fix 6: docker container prune | Bulk cleanup |
| Want crash recovery with same name | Fix 7: Compose restart policy | Daemon manages name |
| Want to keep old for debugging | Fix 8: docker rename | Postpone removal |
If multiple rows apply, pick the topmost one.
Fix 1: Remove the Existing Container
The most common fix. Remove the old container so you can reuse the name:
docker rm my-appIf the container is still running, stop it first:
docker stop my-app
docker rm my-appOr force remove a running container:
docker rm -f my-appThen run your new container:
docker run --name my-app my-imageA reflex I have built for deploy scripts: docker rm -f is my default. It handles running, stopped, and non-existent containers in one command (newer Docker versions do not error on missing containers). Combined with || true for older Docker, it makes deploy scripts idempotent without conditional checks.
Fix 2: Use —rm for Auto-Cleanup
Add --rm to docker run so the container is automatically removed when it stops:
docker run --rm --name my-app my-imageThis is ideal for:
- Development and testing
- One-off commands
- CI/CD pipeline steps
The container is deleted as soon as it exits, so the name is immediately available for reuse.
Note: --rm removes the container and its anonymous volumes. Do not use it if you need to inspect the container’s logs or filesystem after it stops.
Fix 3: Fix Docker Compose Conflicts
Docker Compose manages container names automatically. If you get name conflicts:
Bring everything down cleanly:
docker-compose down
docker-compose up -ddocker-compose down stops and removes containers, networks, and default volumes. This ensures a clean state.
Remove orphaned containers:
docker-compose down --remove-orphansIf the project name changed (directory was renamed):
# Specify the old project name to clean up
docker-compose -p old-project-name down
# Then start with the new name
docker-compose up -dForce recreate containers:
docker-compose up -d --force-recreateThis rebuilds containers even if their configuration has not changed.
A specific habit that has saved me hours: always use docker compose down (not stop) between deployments. stop only halts the containers; down removes them and frees the names. The next up then creates fresh containers instead of trying to reuse the old ones, which avoids subtle “container has different config” warnings and explicit name conflicts.
Fix 4: Use Unique Container Names
If you need to run multiple instances, use unique names:
With timestamps:
docker run --name "my-app-$(date +%s)" my-imageWith random suffixes:
docker run --name "my-app-$(head /dev/urandom | tr -dc a-z0-9 | head -c 6)" my-imageWithout a name (Docker assigns a random name):
docker run my-image
# Docker assigns a name like "hungry_einstein"If you do not need to reference the container by name later, omit --name entirely.
Fix 5: Script-Safe Container Cleanup
In deployment scripts, always clean up before creating:
#!/bin/bash
CONTAINER_NAME="my-app"
# Stop and remove if exists (ignore errors)
docker stop "$CONTAINER_NAME" 2>/dev/null || true
docker rm "$CONTAINER_NAME" 2>/dev/null || true
# Start fresh
docker run -d --name "$CONTAINER_NAME" my-imageOr use docker run --replace (Docker 25.0+):
docker run --replace --name my-app -d my-imageThe --replace flag automatically stops and removes any existing container with the same name before creating the new one. This is the cleanest solution for deployment scripts.
Fix 6: Clean Up All Stopped Containers
Remove all stopped containers at once:
docker container pruneOr with force (no confirmation prompt):
docker container prune -fRemove containers older than 24 hours:
docker container prune --filter "until=24h"List all stopped containers first:
docker ps -a --filter "status=exited"Remove all stopped containers manually:
docker rm $(docker ps -aq --filter "status=exited")For disk space issues from accumulated containers and images, see Fix: Docker no space left on device.
Fix 7: Use Docker Compose Restart Policies
Instead of manually managing container names, use Compose with restart policies:
services:
web:
image: my-app:latest
restart: unless-stopped
container_name: my-app # Optional explicit nameRestart policies:
| Policy | Behavior |
|---|---|
no | Never restart (default) |
always | Always restart, including after Docker daemon restart |
unless-stopped | Restart unless manually stopped |
on-failure | Restart only on non-zero exit code |
With restart: unless-stopped, the container automatically restarts after crashes or Docker daemon restarts. You rarely need to docker run again.
Fix 8: Rename Instead of Remove
If you want to keep the old container for debugging:
docker rename my-app my-app-old
docker run --name my-app my-imageLater, inspect the old container:
docker logs my-app-old
docker inspect my-app-oldAnd remove it when done:
docker rm my-app-oldThis pattern is especially useful in production when a container crashes mid-deployment. Rename the broken one with a timestamp suffix (my-app-broken-20260522), let the deployment continue with the original name, then dig through logs and the filesystem at your own pace before removing the renamed shell.
Stranger Causes I Have Tracked Down
If the error persists after removing the container:
Check for the container in a different Docker context:
docker context ls
docker context use defaultIf docker ps -a shows nothing but docker run --name my-app still conflicts, you are almost certainly looking at the wrong context. Switch to each context in turn and run docker ps -a --filter "name=^my-app$" until you find where the name is held.
Check for Swarm service conflicts. In Docker Swarm mode, services have their own naming. A service container might conflict with a standalone container name.
Check for Docker Desktop bug. On macOS/Windows, Docker Desktop occasionally has stale state. Restart Docker Desktop:
# macOS
osascript -e 'quit app "Docker"' && open -a Docker
# Windows
Restart-Service dockerCheck WSL2 for zombie containers from a previous session. If you use Docker Desktop with the WSL2 backend, a wsl --shutdown followed by a new shell can leave Docker thinking containers that were transitioning to exited are still alive. Force a full Docker Desktop restart from the tray icon rather than just closing the terminal.
Check for docker compose (v2) vs docker-compose (v1) using different project names. Compose v1 (Python) and Compose v2 (Go, shipped with modern Docker) hash project names slightly differently when the directory has unusual characters. Running docker-compose up and then docker compose up (note the space) can create two sets of containers with names that look identical but are not; one removal can leave the other intact.
Check for permission issues on the Docker socket. If you see permission errors when trying to remove containers, see Fix: Docker permission denied socket.
Check for port conflicts. If the name is free but the container still cannot start, the port might be in use. See Fix: Docker port is already allocated.
Reset the Docker state file as a last resort. On Linux you can stop the daemon, move /var/lib/docker/containers/<id>/ for the stuck container aside, and restart the daemon. Do not do this on a system with containers you cannot afford to lose; it is destructive and intended for the case where the daemon’s view of reality is permanently corrupted.
If the Docker daemon itself is not running, see Fix: Docker daemon is not running. If your container starts but exits immediately and leaves the name held, the underlying app may be crashing; see Fix: Docker no space left on device for one common cause, and check the container’s logs with docker logs <name> before assuming it is a name-conflict problem.
What Other Tutorials Get Wrong About This Error
Most Docker tutorials list the same fixes but frame them in ways that produce subtle bugs.
They jump to docker rm without explaining --rm or --replace. For dev workflows, docker run --rm auto-cleans without ceremony. For deploys, docker run --replace (Docker 25+) atomically swaps. Tutorials that only show post-hoc rm send readers into manual cleanup cycles.
They omit docker context. If you switch between Docker Desktop and host Docker, the same name can exist in both contexts. Tutorials that focus only on docker ps -a miss that context can hide the conflict.
They confuse docker compose stop and docker compose down. stop halts containers but keeps them; down removes them and frees names. Tutorials that use stop between deploys leave readers with name conflicts that down would have prevented.
They miss CI suffix patterns. Parallel jobs on shared runners collide unless container names include a unique suffix. Articles that show --name my-app examples in CI workflows produce sporadic failures.
They omit Compose v1 vs v2 namespace differences. docker-compose (Python v1) and docker compose (Go v2) hash project names slightly differently for unusual characters. Tutorials that show both interchangeably leave readers with phantom containers.
They miss Swarm service vs standalone conflicts. Docker Swarm services have their own naming; a Swarm task can conflict with a standalone container named identically. Articles that only address standalone containers miss this case.
Frequently Asked Questions
What is the difference between docker rm and docker run --rm?
docker rm removes a container after the fact (you specify the name). docker run --rm schedules automatic removal when the container exits (no manual cleanup needed). Use --rm for one-off commands; use docker rm for explicit removal of named containers.
Does docker stop free the name?
No. docker stop halts a running container but keeps it in Docker’s container store. The name slot is still occupied. To free the name, also run docker rm after docker stop. Or use docker rm -f to do both in one command.
Should I use docker run --replace in production?
Yes, when on Docker 25+. The --replace flag atomically stops and removes any existing container with the same name before creating the new one. It is the cleanest pattern for deploy scripts because it handles both “container exists” and “container does not exist” cases without conditional logic.
Why does the same name conflict happen across multiple Docker contexts?
Each Docker context (Docker Desktop, host Docker, remote Docker) has its own daemon and its own container namespace. The name my-app can exist in all of them. docker rm only affects the active context. Check docker context ls and switch with docker context use <name> to confirm where the name is held.
Can I run two containers with the same name in different Compose projects?
Yes, but only if you do not set container_name explicitly. Compose generates names like <project>-<service>-<index> by default, which include the project name. If you set container_name: my-app, the two projects collide.
Why does my container come back after I removed it?
It has a restart: always policy. When the Docker daemon restarts (after a host reboot or Docker Desktop restart), restarted containers come back automatically. To prevent this, change the policy to unless-stopped or no, or remove the container with docker rm -f AFTER stopping the daemon.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Fly.io Deploy Not Working — fly.toml, Machines, Volumes, Secrets, and Internal DNS
How to fix Fly.io errors — fly.toml app vs name confusion, machines API vs legacy apps, Dockerfile build failures, volume per-region, secrets staging, fly proxy for local access, and internal IPv6 routing.
Fix: Docker Compose Watch Not Working — sync vs rebuild, Ignore Patterns, WSL/macOS File Events
How to fix docker compose watch errors — develop.watch directive not firing, sync vs sync+restart vs rebuild differences, ignore globs not matching, WSL2 file events delayed, named volumes shadowing watch, and Compose version requirements.
Fix: Coolify Not Working — Deployment Failing, SSL Not Working, or Containers Not Starting
How to fix Coolify self-hosted PaaS issues — server setup, application deployment, Docker and Nixpacks builds, environment variables, SSL certificates, database provisioning, and GitHub integration.
Fix: Docker Secrets Not Working — BuildKit --secret Not Mounting, Compose Secrets Undefined, or Secret Leaking into Image
How to fix Docker secrets — BuildKit secret mounts in Dockerfile, docker-compose secrets config, runtime vs build-time secrets, environment variable alternatives, and verifying secrets don't leak into image layers.