error mounting ... to rootfs at "/etc/alpine-release": ... not a directory: Are you trying to mount a directory onto a file (or vice-versa)? came up here when the host file named in -v did not exist. Docker Desktop created a folder with that name on the host and then could not mount a folder over a file in the image. Create the file, move the folder aside, and run again.

Look in the folder you ran from: the "file" you meant to mount is now an empty directory. Move it aside or delete it, put the real file in its place, and the same docker run works.

The error

The host paths are shortened with ...; the rest is as captured.

PS> docker run --rm --name fix9-run-cfg -v ./app.conf:/etc/alpine-release alpine cat /etc/alpine-release
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/run/desktop/mnt/host/c/.../lab3b/app.conf" to rootfs at "/etc/alpine-release": mount src=/run/desktop/mnt/host/c/.../lab3b/app.conf, dst=/etc/alpine-release, dstFd=/proc/thread-self/fd/14, flags=MS_BIND|MS_REC: not a directory: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
...
Run 'docker run --help' for more information

Why it happens

Before the run the lab folder was empty: there was no app.conf. After the failed run, Get-ChildItem showed app.conf with mode d-----, a directory. The target, /etc/alpine-release, is a file in the image, so the mount was a directory onto a file and runc refused it with the message above.

The message suggests a type mix-up, and that is what it is, but the directory was not yours: Docker made it from the missing path, and it stays on disk after the failed run. The same happened with --mount type=bind,source=./missing.conf,... on this engine: the error was identical and missing.conf existed afterwards as well.

The fix

PS> Get-ChildItem -Force | Format-Table Mode,Name -AutoSize | Out-String

Mode   Name
----   ----
d----- app.conf

PS> Test-Path ./app.conf -PathType Container
True

PS> Move-Item ./app.conf ./app.conf.made-by-docker

PS> Set-Content -Path ./app.conf -Value "3.99.9-fix9" -Encoding ascii

PS> docker run --rm --name fix9-run-cfg -v ./app.conf:/etc/alpine-release alpine cat /etc/alpine-release
3.99.9-fix9

The container printed the host file, so the mount worked. In a real project the file is often a config such as nginx.conf or appsettings.json. Check the spelling and the folder you run from: in this test a source path that did not exist was enough to produce the empty directory, so a typo in the name has the same effect.

How it was reproduced

On Windows 11 with Docker Desktop, engine and client 29.9.3, from Windows PowerShell 5.1, with the cached alpine image, in an empty scratch folder. -v ./app.conf:/etc/alpine-release with no app.conf on disk gave the error and left an app.conf directory; creating the file after moving that directory aside fixed it. The --mount form with a missing missing.conf gave the same result. The folder and container names are the test's own.

Frequently asked

Why did Docker create a folder instead of my config file?
The host file named in -v did not exist. In this test Docker Desktop created a directory with that name, and the mount then failed because the target in the image is a file.
How do I mount a single file into a Docker container?
Make sure the host file exists first, then use -v ./app.conf:/path/in/container. In this test that printed the host file's content from inside the container.
Does --mount avoid the empty folder?
Not in this test. With Docker Desktop 29.9.3 on Windows, --mount type=bind with a missing source file gave the same error, and afterwards Test-Path ./missing.conf -PathType Container returned True: a directory with that name.

More decoded errors in the Fixes category. A related bind mount error with a Linux-style path on Windows: bind source path does not exist.