Overview
The Docker error invalid mount config for type "bind": source path must be a directory means the host-side path you provided for a bind mount is either missing, not a directory (when Docker expects one), or incorrectly specified for your OS/shell.
This guide shows quick checks, a minimal working example, and platform-specific fixes for docker run and Docker Compose.
Quickstart: Fix it fast
- Verify the host path exists and is a directory:
- Linux/macOS:
ls -ld ./srcorls -ld /abs/path/src - Windows PowerShell:
Get-Item .\src
- Linux/macOS:
- Create it if missing:
mkdir -p src(PowerShell:New-Item -ItemType Directory src) - Use absolute or correctly quoted relative paths:
- Linux/macOS (bash/zsh):
--mount type=bind,src="$(pwd)/src",target=/app/src - PowerShell:
--mount type=bind,source="$PWD\src",target=/app/src
- Linux/macOS (bash/zsh):
- If you intend to mount a single file, ensure the container target is a file path, not a directory:
- Example:
-v "$(pwd)/.env":/app/.env
- Example:
Minimal working example (MWE)
This example demonstrates a correct bind mount of a directory using both docker run and Compose.
- Host layout we want:
./src/hello.txt - Container target:
/app/src
Create files:
mkdir -p src
printf "hello from host\n" > src/hello.txt
Dockerfile (optional, for a simple demo):
FROM alpine:3.20
WORKDIR /app
CMD ["sh", "-c", "ls -la /app/src && echo --- && cat /app/src/hello.txt"]
Run with docker build + run:
docker build -t bind-demo .
docker run --rm \
--mount type=bind,src="$(pwd)/src",target=/app/src \
bind-demo
Compose equivalent (docker-compose.yaml):
services:
app:
image: alpine:3.20
working_dir: /app
command: sh -c "ls -la /app/src && echo --- && cat /app/src/hello.txt"
volumes:
- type: bind
source: ./src
target: /app/src
Run:
docker compose up --remove-orphans --force-recreate
If you see the directory listing and the file contents, the bind mount is working.
Common root causes and fixes
Source directory does not exist
- Symptom: The error in question or "no such file or directory".
- Fix: Create it before running:
mkdir -p ./src.
You passed a file path but targeted a container directory
- Symptom: Error insists source must be a directory.
- Fix: When mounting a single file, target a file path. Example:
docker run --rm -v "$(pwd)/.env":/app/.env alpine:3.20 cat /app/.env
Relative paths resolved from the wrong directory
- Symptom: Works in one folder but not another.
- Fix: Use absolute paths or ensure you run commands from the correct directory.
Misquoting or shell expansion issues
- Symptom: The path gets split or misparsed.
- Fix: Quote paths with spaces. On Linux/macOS use
"$(pwd)/src". On PowerShell use"$PWD\src".
Windows drive letter and colon handling
- Symptom: Colons confuse the
-vdelimiter. - Fix: Prefer
--mountwithsource=C:\path\to\dirin PowerShell or CMD; ensure proper quoting.
- Symptom: Colons confuse the
Git Bash/MSYS path conversion on Windows
- Symptom: Paths like
C:\are auto-converted and break mounts. - Fix: Prefix command with
MSYS_NO_PATHCONV=1and use POSIX-style$PWD:MSYS_NO_PATHCONV=1 docker run --rm -v "$PWD/src":/app/src alpine:3.20 ls -la /app/src
- Symptom: Paths like
Compose uses project directory as base for relative paths
- Symptom:
source: ./srcresolves relative to the compose file, not your shell. - Fix: Run from the compose file directory or use an absolute
source.
- Symptom:
Target directory inside container does not exist and image expects it
- Symptom: Command in container references a path that is not present.
- Fix: Either ensure the image creates it or mount to an existing path.
docker run vs --mount vs -v
--mountis key=value and explicit; better for complex cases and Windows.-v(or--volume) is shorter but uses colon-delimited syntax that can collide with Windows drive letters.- Both support file and directory bind mounts, but ensure the source matches the intended type and target path.
Examples:
# Directory mount (Linux/macOS)
docker run --rm --mount type=bind,src="$(pwd)/src",target=/app/src alpine:3.20 ls -la /app/src
# Directory mount (PowerShell)
docker run --rm --mount type=bind,source="$PWD\src",target=/app/src alpine:3.20 ls -la /app/src
# Single file mount (Linux/macOS)
docker run --rm -v "$(pwd)/.env":/app/.env alpine:3.20 cat /app/.env
Compose specifics
- Relative
source:is resolved from the compose file directory. - File mounts are allowed; ensure target is a file path.
- Use long syntax for clarity:
services:
web:
image: nginx:stable
volumes:
- type: bind
source: ./config
target: /etc/nginx/conf.d
If you really want Docker to create the host directory automatically, consider using a named volume instead of a bind mount:
services:
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
OS-specific notes
- Linux
- Paths are straightforward. Ensure proper permissions. For SELinux, add
:Zor:zto relabel if permission denied.
- Paths are straightforward. Ensure proper permissions. For SELinux, add
- macOS
- Docker Desktop file sharing must allow your path (usually under your home directory). Avoid mounting from excluded locations.
- Windows
- Prefer PowerShell or CMD for Docker CLI. Use
--mountwhen possible. Ensure the drive is shared in Docker Desktop.
- Prefer PowerShell or CMD for Docker CLI. Use
Verification checklist
- Does the host source path exist and is it a directory (or file) as intended?
- Are you using the correct shell quoting for your OS?
- Is the container target a matching type (directory vs file)?
- For Compose, is
source:resolved from the compose file directory?
Performance notes
- Bind mounts on macOS/Windows are slower than on Linux due to filesystem virtualization.
- For high I/O workloads:
- Prefer named volumes for application data.
- Minimize the number of bind-mounted files/directories.
- On Docker Desktop, use
:cachedor:delegatedwhere supported to trade consistency for speed.
- Keep source directories small to reduce change detection overhead.
Pitfalls
- Trailing slashes rarely change behavior, but be consistent and avoid ambiguous targets.
- Hidden characters in paths (non-ASCII or zero-width) can break mounts; rename if necessary.
- Mounting into system directories can mask important files in the container; pick dedicated targets.
Tiny FAQ
- Can I bind-mount a single file?
- Yes. Use a file path for both source and target:
-v /host/file:/container/file.
- Yes. Use a file path for both source and target:
- Why does it work with
-vbut not--mount(or vice versa)?- Often due to quoting or Windows path parsing. Prefer
--mountfor clarity on Windows.
- Often due to quoting or Windows path parsing. Prefer
- Compose says the path is invalid, but docker run works.
- Relative path bases differ. Use absolute
source:or run from the compose file directory.
- Relative path bases differ. Use absolute
- Do I need to pre-create the container target path?
- Not always, but creating the host source directory and choosing a sensible container target avoids surprises.