You copy entrypoint.sh into the image, set it as the ENTRYPOINT, build, run, and get:
$ docker run --rm crlf-demo
exec /entrypoint.sh: no such file or directory
You open a shell in the image and the file is exactly where it should be. The error message is technically true, but it's talking about a different file. Here are three errors from the same family, each reproduced on Docker Engine 29.9, with what they actually mean.
1. no such file or directory: the script has Windows line endings
This one hits almost everyone who builds images on Windows. Look at the bytes of the script:
$ od -c entrypoint.sh | head -n 2
0000000 # ! / b i n / s h \r \n e c h o
0000020 " h e l l o f r o m e n t r
The first line ends with \r \n (CRLF). When the kernel runs the script, it reads the interpreter from the shebang line up to the \n, so it looks for a program called /bin/sh\r, with an invisible carriage return at the end. That program doesn't exist, and the "no such file" in the error is about the interpreter, not your script.
Fixes, from most to least durable:
- Tell Git to always check out shell scripts with LF. By default, Git for Windows converts text files to CRLF on checkout. Add a
.gitattributesfile at the repository root:
*.sh text eol=lf
Files you already have checked out keep their CRLF until you convert them once, so also fix the existing script.
In your editor, switch the file to LF. In VS Code, click
CRLFin the status bar and chooseLF.As a safety net in the Dockerfile, strip the carriage returns while building:
COPY entrypoint.sh /entrypoint.sh
RUN sed -i 's/\r$//' /entrypoint.sh
2. permission denied: the script isn't executable
Same setup, different error:
$ docker run --rm noexec-demo
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: exec: "/entrypoint.sh": permission denied
The file has no execute bit. That's easy to miss when the script was created on a filesystem that doesn't store Unix permissions, or came out of a zip, a download or a CI artifact. Most of that long message is just the layers the error passed through (daemon → containerd shim → runc); the useful part is at the end.
The cleanest fix is to set the mode while copying, which needs no extra layer:
COPY --chmod=755 entrypoint.sh /entrypoint.sh
On Linux or macOS you can also run chmod +x entrypoint.sh before building, and Git will keep that bit.
3. executable file not found in $PATH: the image doesn't have that shell
$ docker run --rm alpine:3.23 bash
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: exec: "bash": executable file not found in $PATH
Alpine ships sh (BusyBox), not bash. The same error appears when the program in CMD is misspelled or was never copied into the image.
Use sh, or install bash explicitly:
RUN apk add --no-cache bash
If your script uses bash-only syntax but starts with #!/bin/sh, it will run under BusyBox sh and fail in other, more confusing ways, so make the shebang match the shell you actually need.
A quick checklist
When a container won't start and the message mentions a file you can see:
-
od -c script.sh | head -n 1: is there a\rbefore the\n? -
ls -linside the image (docker run --rm --entrypoint ls image -l /entrypoint.sh): is there anxin the mode? - Does the shebang's interpreter exist in the image? Try
docker run --rm --entrypoint sh image -c 'command -v bash'. - Read the error from the end: the last
exec: ...part names the thing that actually failed.
I keep a page of nearly 30 common Docker errors like these, each reproduced with real output and a fix, as part of a free Docker tutorial: Docker error messages: causes and fixes.
Top comments (1)
The .gitattributes fix is the one I would keep. It stops the CRLF problem for the whole team, instead of fixing one file after each checkout.