Main Ecosystems
HomePython CorePandas ReferenceNumPy ScientificFastAPI & PydanticDjango Enterprise
More Ecosystems
Environment & SetupRequests & HTTPAsyncIO ConcurrencyObject-Oriented OOPPyTorch Deep LearningScikit-Learn MLFlask FrameworkWeb ScrapingDatabase & ORMDevOps & Docker

Docker Error: OCI runtime create failed: unable to start container process: executable file not found

Verified FixPython 3.10+Docker 20+ / LinuxSilo: devops

Quick Fix / Solution Rapide

Convert entrypoint shell scripts from Windows CRLF (\r\n) to Unix LF (\n) line endings using .gitattributes or dos2unix, and ensure chmod +x entrypoint.sh.

Root Cause Analysis

This error occurs when Python or the Docker container runtime (runc) tries to launch a container's entrypoint script, but the Linux kernel cannot execute the file because Windows carriage return line endings (\r\n) corrupted the shebang interpreter line (#!/bin/sh\r), making Linux look for an executable literally named sh\r which does not exist.

The Windows CRLF Shebang Trap

On Windows workstations, text editors (and Git checkouts without .gitattributes) save shell scripts with DOS/Windows line endings (\r\n / CRLF). When a file starting with #!/bin/sh\r\n is copied into a Linux Docker container image via COPY entrypoint.sh .:

  1. The Linux kernel's ELF binary loader reads the shebang line to find the interpreter.
  2. It interprets /bin/sh\r as the full interpreter path (including the invisible carriage return character \r / \x0d).
  3. Since no file named /bin/sh\r exists in /bin, runc fails with OCI runtime create failed: runc create failed: unable to start container process: exec: ".": executable file not found in $PATH.

Other Common Causes

  • Missing Execute Permissions: Creating a shell script on Windows that lacks the Linux execute permission bit (chmod +x).
  • JSON Exec Form vs Shell Form Syntax in Dockerfile: Writing ENTRYPOINT ["./entrypoint.sh"] when the script was copied to /app/entrypoint.sh without a matching WORKDIR /app.

Reproduction Code (MCVE)

Example: Bug Reproduction
# Simulates runtime failure when an entrypoint shebang contains carriage return \r\n
shebang = b'#!/bin/sh\r\n'
if b'\r' in shebang:
    raise RuntimeError('OCI runtime create failed: unable to start container process: exec: ".": executable file not found')

Solution 1: Enforce Unix LF Line Endings via `.gitattributes`

Add a .gitattributes file to the root of your repository to ensure Git always checks out shell scripts with Unix LF line endings across all operating systems.

Example: Recommended Solution
gitattributes_content = '''
# Enforce LF line endings for all shell scripts in Docker builds
*.sh text eol=lf
Dockerfile text eol=lf
requirements.txt text eol=lf
'''

print('Configured .gitattributes rules:')
print(gitattributes_content.strip())

Solution 2: Use Explicit Shell Invocation in Dockerfile

Invoke the shell interpreter directly in the Dockerfile ENTRYPOINT or convert the script using dos2unix in the Docker build step.

Example: Alternative Solution
dockerfile_snippet = '''
# Method A: Direct shell interpreter invocation
ENTRYPOINT ["/bin/sh", "/app/entrypoint.sh"]

# Method B: Clean line endings during Docker image build
RUN apt-get update && apt-get install -y dos2unix \
    && dos2unix /app/entrypoint.sh \
    && chmod +x /app/entrypoint.sh
'''

print('Recommended Dockerfile entrypoint configurations:')
print(dockerfile_snippet.strip())

Note de reproductibilité

La reproductibilité de cette erreur dépend du système d'exploitation de développement (Windows vs macOS/Linux) et de la configuration des fins de ligne (CRLF vs LF) par Git lors du clonage du projet.

Edge Cases & Docker Multi-Stage Permissions

When copying files between stages in multi-stage Docker builds (COPY --from=builder /app /app), permissions can be altered. Always use COPY --chmod=755 --from=builder /app/entrypoint.sh /app/entrypoint.sh in modern Docker BuildKit to guarantee execution bits.

Contrasting OCI runtime create failed with Container exited with code 127: Both relate to missing executables, but OCI failure happens before the container process even spawns, whereas exit code 127 happens after the container started and a command inside the script was not found.