A stopped (or running) container already holds the name — names are unique regardless of state. Decide deliberately: reuse the existing one, or remove it before recreating. --force on rm is where foot-guns live.
Stopping doesn't remove: docker ps -a lists it. Names persist until the container is removed, so every re-run of a --name'd docker run collides with the earlier attempt.
A container with restart=always that failed may look dead in ps but still hold the name. Or another compose project pinned the name explicitly.
docker ps -a --filter name=<name> --format 'table {{.ID}}\t{{.Status}}\t{{.Image}}'
docker rm -f <name> # -f stops it first if running
docker exec -it <name> sh # or docker start <name> if stopped
docker rm -f <name> 2>/dev/null; docker run -d --name <name> ... # or use compose, which recreates by definition
docker run --rm removes on exit but does nothing for a previous container that still holds the name — the cleanup has to target the OLD container, not the new run. Compose manages this by design: up -d recreates. Manual docker run scripts need the rm-first pattern or random/volatile names.
Random names make everything downstream harder (logs, exec, networking by name). Deterministic names + explicit cleanup is the stable pattern; random names trade a collision for an unfindable container.
Only to that container: -f stops a running container to remove it. If something's genuinely serving traffic under that name, you just killed production — filter first, force second.
A production-shaped compose stack: healthchecks, resource limits, log rotation. Never debug a boot race again.
Docker Production Starter — $19 →One-time. Yours to modify. Instant download from the NinjaOps template store.