Skip to content
DevOps AI ToolKit
Newsletter
All guides
Docker with AI By James Joyner IV · · 9 min read

Docker Error Guide: 'invalid mount config for type "bind"' Bind Mount Failures

Fix Docker's invalid mount config for type bind error: create missing host paths, use absolute paths, enable Desktop file sharing, and set SELinux labels.

  • #docker
  • #troubleshooting
  • #errors
  • #volumes

Exact Error Message

Docker prints this when you start a container with a bind mount whose host source path cannot be resolved:

docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /path

Closely related wordings you may also see, depending on how the mount was specified:

Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /home/user/data
Error response from daemon: invalid mount config for type "bind": field Source must not be empty
Error response from daemon: invalid mount config for type "bind": mount type 'bind' not supported on this platform

All four are the daemon refusing a type=bind mount because the host-side source is missing, empty, or unusable.

What It Means

A bind mount maps a directory or file that already exists on the host into the container. Unlike a named volume, the Docker daemon does not create the host path for you when you use --mount — it validates that the source exists and errors out if it does not. (The legacy -v shorthand historically auto-created missing host directories; modern --mount is strict, which is the most common source of confusion.)

The daemon resolves the source path on the host filesystem the daemon runs on, not your shell’s working directory or, on Docker Desktop, your laptop’s raw filesystem. So “the folder is right there” can still fail if the path is relative, if Desktop has not shared that part of your disk, or if SELinux blocks the label. The container never starts; you get the daemon error and nothing in docker logs because no container layer was ever created.

This is also why the same command can behave differently on a teammate’s machine or in CI. The CLI passes the source path to the daemon largely as-is, and it is the daemon that does the existence check. On a native Linux host the daemon and your shell share one filesystem, so an absolute path that exists locally will exist for the daemon too. On Docker Desktop, the daemon lives inside a lightweight Linux VM, and only the directories you have explicitly shared are visible inside that VM — everything else simply “does not exist” from the daemon’s point of view, even though you can ls it in your terminal. Understanding that split between where you type the command and where the daemon evaluates the path explains most bind-mount surprises.

Common Causes

  • Host source path does not exist. With --mount, Docker will not auto-create it. The directory must exist before docker run.
  • Relative instead of absolute path. -v ./data:/app or --mount source=data,... resolves against the daemon’s notion of the path, not your cwd, and fails.
  • field Source must not be empty. A shell variable expanded to an empty string (-v $DATA_DIR:/app where DATA_DIR is unset), leaving no source.
  • Docker Desktop file sharing not enabled. On macOS/Windows the path lives outside the shared file-sharing roots, so the VM cannot see it.
  • SELinux relabeling. On RHEL/Fedora the mount succeeds but the container is denied access unless you add :z (shared) or :Z (private) to relabel the source.
  • Mixing -v auto-create with --mount strict semantics across scripts, so the same path works in one command and fails in another.
  • Windows path format. C:\Users\me\data must be /c/Users/me/data (or //c/...) for the Linux daemon.
  • Permissions. The path exists but the daemon user cannot stat it (e.g. inside a restricted mount namespace).

How to Reproduce the Error

Point a bind mount at a directory that does not exist, using the strict --mount form:

docker run --rm \
  --mount type=bind,source=/tmp/does-not-exist-1234,target=/data \
  alpine ls /data
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /tmp/does-not-exist-1234.

Reproduce the empty-source variant with an unset variable:

unset DATA_DIR
docker run --rm --mount type=bind,source=$DATA_DIR,target=/data alpine true
docker: Error response from daemon: invalid mount config for type "bind": field Source must not be empty.

Diagnostic Commands

First confirm whether the host path actually exists and is a directory the daemon can read:

ls -ld /tmp/does-not-exist-1234
readlink -f ./data            # resolve a relative path to its absolute form
ls: cannot access '/tmp/does-not-exist-1234': No such file or directory

Inspect what mounts a running or created container was asked for:

docker inspect <container> --format '{{json .Mounts}}' | python3 -m json.tool
docker inspect <container> --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}}{{println}}{{end}}'

On Docker Desktop, confirm the daemon’s platform and storage driver, and check the file-sharing roots in Settings → Resources → File Sharing:

docker info --format 'Server: {{.OperatingSystem}} | Driver: {{.Driver}} | Root: {{.DockerRootDir}}'
docker info | grep -i -A3 'file sharing\|operating system'

If the daemon itself looks unhealthy while resolving mounts, check its logs:

journalctl -u docker --no-pager -n 50
docker events --since 5m --filter event=create

Step-by-Step Resolution

1. Create the host path before running. Bind sources are not auto-created with --mount:

mkdir -p /srv/app/data
docker run --rm --mount type=bind,source=/srv/app/data,target=/data alpine ls -la /data

2. Always use absolute paths. Expand relative paths yourself so the daemon and your shell agree:

docker run --rm -v "$(pwd)/data:/data" alpine ls /data
docker run --rm --mount type=bind,source="$(readlink -f ./data)",target=/data alpine ls /data

3. Guard against empty variables to avoid field Source must not be empty:

: "${DATA_DIR:?DATA_DIR must be set}"
docker run --rm --mount type=bind,source="$DATA_DIR",target=/data alpine true

4. Enable Docker Desktop file sharing. In Settings → Resources → File Sharing, add the parent directory (e.g. /Users/me/projects), apply, and restart. On Windows use Linux-style paths: /c/Users/me/data.

5. Add SELinux labels on RHEL/Fedora/CentOS when the container can mount but not read:

docker run --rm -v /srv/app/data:/data:Z alpine ls /data   # :Z private, :z shared

6. Pick the right semantics. Use --mount type=bind when you want the strict, fail-fast behaviour and an existing host path. Use -v host:container only when you accept legacy auto-create of directories. Do not mix the two expectations in the same script.

How to Prevent the Issue

  • Standardize on --mount with absolute, pre-created paths in scripts and Compose files so failures surface early instead of silently auto-creating empty dirs.
  • Validate required directories in your entrypoint or make target (mkdir -p / [ -d ]) before invoking docker run.
  • Quote and default-check every path variable ("${VAR:?}") to eliminate empty-source errors in CI.
  • Document the Docker Desktop file-sharing roots your team needs so new machines are configured once.
  • On SELinux hosts, bake :z/:Z into your run commands and review them so containers do not silently lose access. See more in Docker guides.
Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.