Docker Compose Volume Mount "bind source path does not exist" in CI
A Compose bind mount pointed at a host path that does not exist on the runner. Compose (unlike Docker’s implicit create) refuses to mount a missing bind source, so the container fails to start.
What this error means
A docker compose up fails to start a service with error while creating mount source path / bind source path does not exist: <path>. The compose file is valid; the host directory it binds is simply not there in CI.
Error response from daemon: error while creating mount source path
'/home/runner/work/app/data': bind source path does not exist: /home/runner/work/app/dataDiagnose it: read the resolved config, not the file you wrote
Compose merges override files, interpolates variables, and applies defaults before it does anything. Most Compose failures in CI are visible in the resolved configuration and invisible in the source file, because the value you are debugging came from an unset variable that quietly became an empty string.
# the fully merged, interpolated configuration Compose will actually run
docker compose config
# fail loudly on unset variables instead of silently interpolating empty
docker compose --env-file .env config --quiet || echo "invalid"
# which override files were picked up
docker compose config --services
Common causes
The relative host path is absent on the runner
A ./data:/var/lib/data bind expects ./data to exist relative to the compose file. In a fresh checkout that directory may never have been created.
Wrong volume short-syntax interpreted as a bind
A volumes: entry meant to be a named volume but written as a path (or vice versa) makes Compose treat a missing host path as a bind source.
Path relative to the wrong working directory
Bind sources resolve relative to the compose file’s location; running from elsewhere makes a correct-looking relative path resolve to nothing.
How to fix it
Create the bind source before composing up
Make the host directory exist in the job before starting the services.
mkdir -p ./data
docker compose up -dUse a named volume when no host path is needed
If the data does not need to live on the host, a named volume avoids the bind-source requirement entirely.
services:
db:
volumes:
- dbdata:/var/lib/postgresql/data # named volume, not a host bind
volumes:
dbdata:Bind mounts behave differently on a runner
- A relative bind source is resolved against the compose file location, not the working directory of the shell that invoked it.
- The host path must exist before
up. Compose creates missing directories for named volumes but not for bind mounts, and the failure surfaces as a mount error rather than a missing-path error. - On a CI runner the workspace path differs from your machine, so any absolute host path in a compose file is a portability bug waiting for its first CI run.
- Prefer named volumes for anything that does not genuinely need to be read from the host. They remove the whole class of problem.
How to prevent it
- Create bind-mount host directories in the job before
compose up. - Prefer named volumes when the data need not be a host path.
- Keep bind paths relative to the compose file and run from that directory.