You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] watch says: Error response from daemon: cannot overwrite non-directory "xxx" with directory "yyy" #13795
When I do a docker compose up --watch I get the error:
copying files to dff6....: Error response from daemon: cannot overwrite non-directory "/some/path/in/image" with directory "/"
In this case /some/path/in/image is a relative symlink.
The error occurs only with ---watch which probably means that this is an issue with the initial sync of compose watch.
Steps To Reproduce
Unfortunately I have not managed to reproduce the issue, but I have seen it multiple times.
It always occurs after switching to a Git commit where folder structure is entirely different.
The first time I was able to fix it by running docker system prune. The second time by docker compose build --no-cache.
The error occurs only with --watch. I can start containers successfully without watch.
Compose Version
$ docker compose version
Docker Compose version v5.1.3
I dug into where this error comes from. It's the watch sync step, not the build, which is why a plain up works and only --watch hits it.
When watch syncs changed paths, it builds a tar and unpacks it into the running container through the daemon's CopyToContainer at / (tarDockerClient.Untar in pkg/compose/watch.go). That call doesn't set AllowOverwriteDirWithFile, so the unpack runs with noOverwriteDirNonDir on. If the tar carries a directory entry for a path that already exists in the image as a non-directory (your relative symlink), the daemon refuses and returns exactly:
cannot overwrite non-directory "<path>" with directory "/"
So the condition is a type mismatch at one path: a directory on the host side, a symlink (or file) in the image. docker system prune / build --no-cache clear it only because the rebuilt image no longer has the symlink there.
It's hard to reproduce on demand because the initial sync only ever copies files, never whole directories (initialSyncFiles skips directories on purpose). The directory entry that trips this comes from the regular event-driven sync, e.g. when a directory appears or changes under the watched path, which lines up with it happening "after switching to a commit where the folder structure is entirely different".
Before I open a PR, I'd like to confirm the intended behavior:
Have the watch sync pass AllowOverwriteDirWithFile: true, so it replaces the conflicting symlink/file with the host directory (host as the source of truth, which is what watch is for).
Keep failing, but replace the raw daemon error with a clear message that names the host-directory vs image-symlink conflict.
I'm leaning towards 1, but that would make watch behave differently from docker compose cp, which intentionally keeps the no-overwrite default (AllowOverwriteDirWithFile: false), so I didn't want to change the behavior without checking.
Happy to send the PR with a regression test for whichever you'd prefer.
Activity
adityasharmawork commentedon May 31, 2026
Hey Maintainers!
I dug into where this error comes from. It's the watch sync step, not the build, which is why a plain
upworks and only--watchhits it.When watch syncs changed paths, it builds a tar and unpacks it into the running container through the daemon's
CopyToContainerat/(tarDockerClient.Untarinpkg/compose/watch.go). That call doesn't setAllowOverwriteDirWithFile, so the unpack runs withnoOverwriteDirNonDiron. If the tar carries a directory entry for a path that already exists in the image as a non-directory (your relative symlink), the daemon refuses and returns exactly:cannot overwrite non-directory "<path>" with directory "/"So the condition is a type mismatch at one path: a directory on the host side, a symlink (or file) in the image.
docker system prune/build --no-cacheclear it only because the rebuilt image no longer has the symlink there.It's hard to reproduce on demand because the initial sync only ever copies files, never whole directories (
initialSyncFilesskips directories on purpose). The directory entry that trips this comes from the regular event-driven sync, e.g. when a directory appears or changes under the watched path, which lines up with it happening "after switching to a commit where the folder structure is entirely different".Before I open a PR, I'd like to confirm the intended behavior:
AllowOverwriteDirWithFile: true, so it replaces the conflicting symlink/file with the host directory (host as the source of truth, which is what watch is for).I'm leaning towards 1, but that would make watch behave differently from
docker compose cp, which intentionally keeps the no-overwrite default (AllowOverwriteDirWithFile: false), so I didn't want to change the behavior without checking.Happy to send the PR with a regression test for whichever you'd prefer.