Skip to content
| Marketplace
Sign in
Visual Studio Code>Linters>EntryCheck: Fix exec format error in Docker & CI ScriptsNew to Visual Studio Code? Get it now.
EntryCheck: Fix exec format error in Docker & CI Scripts

EntryCheck: Fix exec format error in Docker & CI Scripts

jaytank_dev

| (0) | Free
Catch "exec format error", "no such file or directory" and "permission denied" before the container or CI run: flags CRLF line endings, missing shebangs, UTF-8 BOMs and non-executable git modes in scripts used by Dockerfile ENTRYPOINT/CMD/RUN, docker-compose, GitHub Actions, GitLab CI, package.json
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

EntryCheck: Fix exec format error in Docker & CI Scripts

Your image builds fine, then the container dies instantly with one of these:

exec /entrypoint.sh: exec format error
/usr/bin/env: 'bash\r': No such file or directory
exec: "./start.sh": permission denied

Nothing is wrong with the logic. The script has Windows line endings, a missing shebang, an invisible UTF-8 BOM, or it was committed without the executable bit. EntryCheck finds the scripts your Dockerfiles, compose files, CI workflows, npm scripts and git hooks actually execute, and flags those problems right on the line that runs them - before you push.

What it checks

Rule Severity Problem Fix
EC001 Error CRLF line endings in a script that runs on Linux Quick Fix: convert to LF, or add *.sh text eol=lf to .gitattributes
EC002 Error Directly-executed script has no #! shebang, or the interpreter is not an absolute path Add e.g. #!/bin/sh or #!/usr/bin/env bash
EC003 Error UTF-8 BOM before the shebang hides #! from the kernel Quick Fix: strip the BOM
EC004 Warning Script is mode 100644 in git, so it is not executable after checkout git update-index --chmod=+x path/to/script.sh or RUN chmod +x in the Dockerfile
EC005 Information No .gitattributes eol rule for shell scripts Quick Fix: add *.sh text eol=lf

Each diagnostic sits on the referencing line (for example the ENTRYPOINT in your Dockerfile) and links to the script itself.

  • Activity bar: an EntryCheck view lists every failing script, grouped by the file that launches it (Dockerfile, compose file, workflow, package.json, Husky hook). Each row names the rule and the exact script, for example EC001 docker/entrypoint.sh, with the rule and line next to it. Click a row to jump to the launching line. Inline buttons convert the script to LF, strip the BOM, add the .gitattributes rule or open the script. The icon shows a badge with the number of problems.

Where it looks

  • Dockerfile / Containerfile - ENTRYPOINT, CMD and RUN, in exec form (["/entrypoint.sh"]), shell form, ["sh", "-c", "..."] and RUN <<EOF heredocs. Container paths are mapped back to your build context through COPY/ADD (directories, globs, --chmod), WORKDIR, multi-stage COPY --from=<stage> and RUN --mount=type=bind. A bare name such as ENTRYPOINT ["docker-entrypoint.sh"] is looked up in the usual PATH folders (/usr/local/bin and friends).
  • docker-compose - entrypoint: and command: in string or list form. These paths live inside the container, so they are resolved through the service's bind mounts (volumes:), then through its Dockerfile (build.context, build.dockerfile, build.target) and working_dir. An absolute path like entrypoint: /opt/start.sh is followed to the file the Dockerfile copied there. The Dockerfile itself is also checked with the build context from the compose file.
  • GitHub Actions - run: steps, including multi-line run: | blocks, with working-directory: (step, job or workflow default) applied. Steps with a non-shell shell: (pwsh, python) are skipped.
  • GitLab CI - script:, before_script: and after_script: entries.
  • package.json - scripts entries that call ./something.sh.
  • Husky - hooks in .husky/. Husky 9 hooks are run with sh, so they are only checked for CRLF and BOM. Older hooks that source husky.sh are run by git and also need a shebang and the executable bit.

Only scripts that are executed directly (./deploy.sh, /entrypoint.sh) are checked for a shebang and the executable bit. Scripts run through an interpreter (sh ./x.sh, bash x.sh) are still checked for CRLF and BOM, which break them too. EC004 is skipped when the Dockerfile already does RUN chmod +x on the file (or its folder with chmod -R) or copies it with COPY --chmod=755.

How this differs

ShellCheck lints the contents of a shell script and hadolint lints Dockerfile instructions. Neither follows an ENTRYPOINT or a CI run: line to the file it points at and checks that file's line endings, BOM, or executable bit in git. EntryCheck is that missing link between the two, and it complements them rather than replacing them.

Privacy and Workspace Trust

EntryCheck only reads, reports on or rewrites files that resolve (after following symlinks) inside the open workspace folder. Script paths from COPY, compose build: and volumes:, CI run: lines or package.json that point outside the project are ignored, and a .gitattributes that is a symlink is never read or changed.

  • No network access and no telemetry. Everything runs locally.
  • The executable-bit check (EC004) reads git's index with git ls-files -s, run without a shell, with core.fsmonitor and hooks disabled and global/system git config ignored. It only runs in trusted workspaces. In an untrusted (Restricted Mode) workspace EntryCheck still runs EC001, EC002, EC003 and EC005, which only read files.
  • Files are only changed when you pick a Quick Fix or an inline button, and never while the file has unsaved changes in the editor.

Commands

  • EntryCheck: Rescan Workspace - rescan all workspace folders. Scans also run automatically on save, when files change, and every few seconds for files that changed outside VS Code.

Settings

  • entrycheck.enabled (default true) - turn all checks off or on.

Limitations

  • Without a compose file, a Dockerfile's build context is assumed to be its own folder.
  • Paths built from variables ($APP_DIR/start.sh, ${{ ... }}) are skipped, and so are files copied from an external image (COPY --from=nginx).
  • A compose entrypoint: with an absolute path is only resolved when the service has a bind mount or a build: whose Dockerfile copies that path. For an image:-only service the script is not in your workspace, so it is skipped.
  • EC002 checks that the shebang is well formed, not that the interpreter exists in your image.

License

MIT - included with the extension.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft