KhueApps
Home/DevOps/Fix Docker bind mount error: source path must be a directory

Fix Docker bind mount error: source path must be a directory

Last updated: October 07, 2025

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

  1. Verify the host path exists and is a directory:
    • Linux/macOS: ls -ld ./src or ls -ld /abs/path/src
    • Windows PowerShell: Get-Item .\src
  2. Create it if missing: mkdir -p src (PowerShell: New-Item -ItemType Directory src)
  3. 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
  4. 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

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 -v delimiter.
    • Fix: Prefer --mount with source=C:\path\to\dir in PowerShell or CMD; ensure proper quoting.
  • Git Bash/MSYS path conversion on Windows

    • Symptom: Paths like C:\ are auto-converted and break mounts.
    • Fix: Prefix command with MSYS_NO_PATHCONV=1 and use POSIX-style $PWD:
      • MSYS_NO_PATHCONV=1 docker run --rm -v "$PWD/src":/app/src alpine:3.20 ls -la /app/src
  • Compose uses project directory as base for relative paths

    • Symptom: source: ./src resolves relative to the compose file, not your shell.
    • Fix: Run from the compose file directory or use an absolute source.
  • 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

  • --mount is 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 :Z or :z to relabel if permission denied.
  • 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 --mount when possible. Ensure the drive is shared in Docker Desktop.

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 :cached or :delegated where 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.
  • Why does it work with -v but not --mount (or vice versa)?
    • Often due to quoting or Windows path parsing. Prefer --mount for clarity on Windows.
  • Compose says the path is invalid, but docker run works.
    • Relative path bases differ. Use absolute source: or run from the compose file directory.
  • 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.

Series: Docker

DevOps