The image builds, the container exits instantly, and the log says:
exec /entrypoint.sh: no such file or directory
ls -l /entrypoint.sh inside the image shows the file right there. So what is missing?
The kernel reads your first line
For a script, execve() reads the #! line and runs the interpreter it names. Four invisible problems break that step:
| In the file | The kernel sees | You get |
|---|---|---|
| CRLF line endings | interpreter /bin/sh\r
|
no such file or directory |
#!/usr/bin/env bash + CRLF |
a program called bash\r
|
/usr/bin/env: 'bash\r': No such file or directory |
| No shebang, or a UTF-8 BOM before it | no #! at all |
exec format error |
Git mode 100644
|
a non-executable file | permission denied |
The missing file is the interpreter, but the message names your script. The usual source is a Windows checkout with core.autocrlf=true: docker build sends that CRLF working tree, and COPY puts it in the image (real example, Moby's request for a better error).
Fix it by hand
file entrypoint.sh # "with CRLF line terminators"?
git ls-files -s entrypoint.sh # 100644 = not executable
sed -i 's/\r$//' entrypoint.sh
echo '*.sh text eol=lf' >> .gitattributes && git add --renormalize .
git update-index --chmod=+x entrypoint.sh
The .gitattributes rule is the part that stops it coming back.
Catch it in the editor
I built EntryCheck, a free VS Code extension that follows Dockerfile ENTRYPOINT/CMD/RUN (through COPY and WORKDIR), compose entrypoint/command, GitHub Actions run:, GitLab CI script:, package.json scripts and Husky hooks to the scripts they execute, and flags:
-
EC001 CRLF line endings (Quick Fix: convert to LF, or add the
.gitattributesrule) - EC002 missing or non-absolute shebang on a directly executed script
- EC003 UTF-8 BOM before the shebang (Quick Fix: strip it)
-
EC004 mode
100644in git, unless the Dockerfile already doeschmod +xorCOPY --chmod=755 -
EC005 no
.gitattributeseol rule for*.sh
The diagnostic lands on the line that launches the script, and a Failing scripts panel in the activity bar lists every problem by script name with one-click fixes. No network, no telemetry, and the git check only runs in trusted workspaces. It does not check that the interpreter exists in your image (#!/bin/bash on Alpine still fails), and it does not follow compose build.context or variable paths.
code --install-extension jaytankdev.entrycheck
Source (MIT): github.com/jay-tank/entrycheck
Full write-up (every error explained, the BOM fix, how it resolves container paths, limitations, FAQ): exec /entrypoint.sh: no such file or directory? Fix CRLF, shebangs and chmod
Top comments (0)