`docker run` can fail with status 125, 126, or 127. What does each of those three values mean, and what kind of mistake causes each?
answer
- 125 = Docker's fault (bad flag/daemon) — nothing ran
- 126 = found, not executable (chmod / exec format error)
- 127 = not found (missing binary, typo, CRLF shebang)
- Same trio as the shell's reserved codes
- alpine has no bash/curl; distroless has no shell
basics
~20 s125 = the docker run command itself failed (bad flag, daemon or image-config error) — no container process ever ran. 126 = the command was found but could not be executed (not executable, bad format). 127 = the command was not found inside the image (typo, missing binary, wrong PATH).
solid answer
~60 sDocker reserves three codes so it can tell you *where* the failure was, before your application code ever gets a chance to fail: - **125 — Docker's own error.** The `docker run` invocation could not create or start the container at all: an unknown flag, a malformed `--mount`, a conflicting name, an invalid config. Nothing inside the image ran. `.State.Error` or the CLI's stderr usually carries the message. - **126 — found but not runnable.** The entrypoint path exists but cannot be exec'd: the script is missing the executable bit, has no shebang or a bad one, or is a binary for the wrong architecture/format (`permission denied`, `exec format error`). - **127 — not found.** The binary named in `ENTRYPOINT`/`CMD` does not exist in the image or is not on `PATH`. Classic causes: assuming `curl`/`bash` exists in an Alpine or distroless image, a typo, or a shell script saved with CRLF line endings so the interpreter path reads as `/bin/sh\r`. The useful mental split: 125 = *my Docker invocation is wrong*; 126/127 = *my image is wrong*.
code
bash · 4 linesdocker run --detached alpine true # 125: unknown flag (--detach is correct)
docker run --rm alpine /etc/hostname # 126: exists, not executable
docker run --rm alpine bash -c 'echo hi' # 127: alpine has no bash
echo $?go deeper
Memorise the split: 125 = my docker command, 126 = file not executable, 127 = file not found.
Add the concrete causes — missing chmod, wrong architecture, missing bash/curl in minimal images — and know nothing from the image ran on 125.
Show the triage loop: read the exact error text, override the entrypoint to inspect the image, and check architecture and libc before rebuilding blindly.
Push these failures left: pin base images, enforce COPY --chmod, normalise line endings in the repo, and add a CI smoke run so 126/127 are caught at build time rather than at deploy.
## Why these three codes exist When you run a container, three separate things must succeed before your program's own exit code means anything: 1. The Docker CLI/daemon must accept your request and create the container. 2. The runtime must locate the executable named by `ENTRYPOINT`/`CMD` inside the container's filesystem. 3. The kernel must be able to `exec` that file. If any of those fail, there is no application exit status to report — so Docker borrows the shell's reserved codes to say which stage broke. This is exactly the convention `bash` uses for the same three situations, which is why the numbers feel familiar. ## 125 — the Docker command itself failed 125 means the failure was on Docker's side of the boundary. Typical triggers: - An unknown or misspelled flag: `docker run --detached nginx` (the flag is `--detach`). - An invalid value: a malformed `--mount` string, a bad `--memory` unit, an unparseable port mapping. - A conflict: `--name` already in use by an existing container. - Daemon-level failures: the requested network doesn't exist, a device or capability can't be set up, the storage driver errors out. The defining property is that **nothing from your image executed**. Anything you observe — no logs, no process — is consistent with that. The CLI prints a message on stderr, and for containers that were created before failing, `docker inspect --format '{{.State.Error}}'` often holds the daemon's explanation. 125 is also what `docker run` returns when the image can't be pulled or the platform doesn't match, so on a mixed amd64/arm64 fleet it shows up during `--platform` mistakes. ## 126 — the command was found but is not executable 126 means the runtime located the file but `exec` refused it. The two big families: **Permission**: the entrypoint script is in the image but has no execute bit. This happens constantly with `COPY entrypoint.sh /usr/local/bin/` from a checkout that lost file modes (Windows filesystems, some archives, some CI checkouts). The fix is `RUN chmod +x /usr/local/bin/entrypoint.sh` or `COPY --chmod=0755`. Error text: `permission denied`. **Format**: the file is not something the kernel can execute — a script with no shebang line invoked directly (rather than via a shell), or a binary compiled for a different architecture or libc. Error text: `exec format error`. On multi-arch estates the classic case is an amd64 binary in an image run on arm64 without emulation, or a Dockerfile that copied a host-built binary into an image with an incompatible base. A subtle one: a directory or a non-executable data file specified as the entrypoint also produces 126. ## 127 — the command was not found 127 means the runtime could not find the executable at all. Sources, in rough order of frequency: - **The binary isn't in the image.** Minimal bases are minimal: `alpine` has no `bash` and no `curl`; `distroless` has no shell at all; `scratch` has nothing. `CMD ["bash", "-c", "..."]` on Alpine yields 127, as does a `HEALTHCHECK` calling `curl` in an image without curl. - **Typos and wrong paths.** `CMD ["/app/serverr"]`, or a binary that lives in `/usr/local/bin` while `PATH` doesn't include it in that context. - **CRLF line endings.** A shell script saved on Windows has `#!/bin/sh\r`, and the kernel dutifully looks for an interpreter literally named `/bin/sh\r`. The error reads `no such file or directory` even though `/bin/sh` obviously exists — a famously confusing 127. - **Missing dynamic libraries.** A dynamically linked binary whose loader is absent (a glibc binary in an Alpine/musl image) can surface as `no such file or directory` and 127, even though the binary file itself is right there. ## Triage order Given a 125/126/127, the fastest path is: 1. **125** — re-read your `docker run` line and the CLI's stderr; nothing about the image matters yet. 2. **126/127** — inspect the image: `docker run --rm --entrypoint sh <image> -c 'ls -l /path; file /path'` (if the image has a shell), or `docker run --rm --entrypoint ls <image> -l /path`. For a shell-less image, `docker export`/`docker save` and look inside, or add a debug stage. 3. Check the exact error text: `permission denied` → chmod; `exec format error` → architecture or shebang; `no such file or directory` on a path that exists → CRLF or a missing interpreter/linker. The payoff for memorising these is speed: three numbers tell you whether to fix your command line, your file permissions, or your image contents — before you read a single application log.
- An entrypoint script clearly exists at the path you specified, yet the container exits 127 with `no such file or directory`. What is going on?The message is about the *interpreter*, not the script. If the file was saved with Windows CRLF line endings, the shebang reads `#!/bin/sh\r` and the kernel looks for a binary literally named `/bin/sh\r`, which does not exist. The same message can also mean the dynamic linker or a required shared library is missing — for instance a glibc-linked binary copied into a musl-based Alpine image. Fix with `dos2unix`/`.gitattributes` for line endings, or match the binary's libc to the base image.
- How do you inspect an image that has no shell to find out why it returns 126 or 127?Override the entrypoint with a binary that does exist — `docker run --rm --entrypoint ls <image> -l /app` — or build a debug variant with a shell-bearing base as a final stage. Alternatively, `docker create` the image and `docker export` it (or use `docker save` and unpack the layers) to list the filesystem from outside. Checking the manifest's architecture with `docker image inspect --format '{{.Architecture}}'` catches the exec-format-error case quickly.
saying these in an interview costs you the question
- Treating 125 as an application failure and hunting through logs that do not exist
- Assuming 127 always means a typo, missing the CRLF-shebang and missing-shared-library cases
- Expecting `bash`, `curl`, or any shell to exist in Alpine/distroless/scratch images
- Confusing 126 and 127 — 126 is found-but-not-runnable, 127 is not-found