Skip to content
DevOps AI ToolKit
Newsletter
All guides
Docker with AI By James Joyner IV · · 9 min read

Docker Error: 'OCI runtime exec failed — executable file not found in $PATH'

Fix Docker's 'OCI runtime exec failed: unable to start container process: exec: executable file not found in $PATH' — install the binary, use an absolute path, or fix exec vs shell form.

  • #docker
  • #troubleshooting
  • #errors
  • #runtime

Exact Error Message

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: exec: "myapp": executable file not found in $PATH: unknown

Common variants — the quoted binary changes, and older/other runtimes word it slightly differently:

... starting container process caused: exec: "bash": executable file not found in $PATH: unknown

OCI runtime exec failed: exec failed: unable to start container process: exec: "psql": executable file not found in $PATH: unknown

What It Means

This is a specific tail of the broader OCI runtime create failed error. The image pulled, the container’s namespaces and filesystem were set up, and then runc tried to launch the first process — the program named by your ENTRYPOINT/CMD (or the command you passed to docker run / docker exec). The runtime searched every directory in the container’s PATH, found no such executable, and refused to start.

The key insight: PATH is evaluated inside the container, using the container’s filesystem — not your host’s. A binary that exists on your laptop, or that you assumed was in the base image, simply isn’t there. Minimal images (scratch, alpine, distroless, busybox) ship almost nothing, so this error is extremely common when moving from a fat base image to a slim one.

There are really two distinct failures hiding under the same message. The first is “the program does not exist in this image at all” — you never installed it, or a multi-stage build left it behind in an earlier stage. The second is “the program exists but the runtime can’t resolve the name you gave it” — it lives in a directory that isn’t on PATH, or you typed bash in an image that only has sh. The diagnostic steps below distinguish these in seconds, and the distinction determines whether you fix the Dockerfile’s install steps or simply fix the path/name you reference.

Common Causes

  • Binary not installed in the image. The ENTRYPOINT/CMD references a tool that was never apt installed / apk added into the final image.
  • bash doesn’t exist — only sh does. Alpine and busybox ship /bin/sh (BusyBox), not /bin/bash. CMD ["bash", ...] fails; CMD ["sh", ...] works.
  • Wrong or relative path. CMD ["myapp"] relies on PATH; if the binary lives in /opt/app/bin and that isn’t on PATH, it’s “not found.”
  • Shell-form vs exec-form confusion. ENTRYPOINT myapp (shell form) runs via /bin/sh -c, which fails differently if sh is absent; exec form ["myapp"] needs the binary directly.
  • PATH not set in a scratch image. With no shell profile, PATH may be empty, so even /usr/bin/myapp isn’t found unless invoked by absolute path.
  • Cross-architecture binary. An amd64 binary copied into an arm64 image won’t execute; the runtime reports it as not found/exec error.

How to Reproduce the Error

Reliable. Ask an Alpine image to run bash, which it does not contain:

docker run --rm alpine bash -c 'echo hi'
# ... exec: "bash": executable file not found in $PATH: unknown

Or reference a binary that was never installed:

docker run --rm alpine psql --version
# ... exec: "psql": executable file not found in $PATH: unknown

Diagnostic Commands

The fastest move is to get a shell in the same image and look for the binary yourself.

# Override the entrypoint and open a shell to inspect the filesystem
docker run --entrypoint sh -it <image>
# inside the container:
echo "$PATH"
command -v myapp || which myapp
ls -l /usr/local/bin /usr/bin | grep myapp

# What did the image's metadata configure as entrypoint/cmd?
docker inspect <image> --format 'ENTRYPOINT={{json .Config.Entrypoint}} CMD={{json .Config.Cmd}} PATH={{json .Config.Env}}'

# Confirm the architecture matches the host
docker inspect <image> --format '{{.Architecture}}'
docker version --format '{{.Server.Arch}}'

Example showing the binary genuinely isn’t present:

/ # echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/ # command -v psql
/ #            <-- empty: psql is not installed anywhere on PATH

Step-by-Step Resolution

  1. Confirm the binary is missing using the shell-override above. If command -v prints nothing, the binary truly isn’t in the image.

  2. Install it in the image. Add it to the Dockerfile of the final stage:

    # Debian/Ubuntu base
    RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client \
        && rm -rf /var/lib/apt/lists/*
    
    # Alpine base
    RUN apk add --no-cache postgresql-client
  3. If it’s a shell mismatch, use sh (or install bash). On Alpine either switch the form or add bash:

    # Option A: use the shell that exists
    CMD ["sh", "-c", "echo hi"]
    # Option B: install bash if you truly need it
    RUN apk add --no-cache bash
  4. Use an absolute path for non-standard locations. If your binary lives outside PATH, reference it fully:

    ENTRYPOINT ["/opt/app/bin/myapp"]
  5. Prefer exec form over shell form. Exec form avoids an implicit /bin/sh dependency and is what production should use:

    # exec form (preferred)
    ENTRYPOINT ["myapp", "--serve"]
    # shell form (needs /bin/sh present)
    ENTRYPOINT myapp --serve
  6. For multi-stage builds, COPY the binary into the final stage. A classic bug: you build in a golang stage but the final scratch/alpine stage never receives the binary.

    FROM golang:1.22 AS build
    WORKDIR /src
    COPY . .
    RUN CGO_ENABLED=0 go build -o /out/myapp .
    
    FROM alpine:3.20
    COPY --from=build /out/myapp /usr/local/bin/myapp
    ENTRYPOINT ["/usr/local/bin/myapp"]
  7. Fix cross-arch mismatches. Build for the target platform: docker buildx build --platform linux/arm64 ..., and don’t COPY a prebuilt host binary of the wrong architecture.

How to Prevent the Issue

  • Use exec form (["binary", "arg"]) and absolute paths for ENTRYPOINT/CMD so resolution never depends on shell or PATH quirks.
  • Remember Alpine/BusyBox/distroless ship sh, not bash — write scripts for POSIX sh or explicitly install bash.
  • In multi-stage builds, verify the final stage COPY --from=... actually pulls every runtime binary it needs.
  • Build static binaries (CGO_ENABLED=0) for scratch/distroless so there’s no shell or loader dependency at all.
  • Match --platform to your deployment architecture in CI to avoid silent cross-arch “not found” failures.
  • Add a one-line health check to CI that runs the image’s entrypoint with --version or --help; if the binary is missing, this fails the build instead of the production deploy.
  • When slimming a base image (moving from ubuntu to alpine or distroless), re-test every command the container actually invokes — package managers, shells, and helper tools you took for granted often vanish in the smaller image.
Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.