| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64 |
| Applies to | Linux hosts with Podman where a container fails to start because the runtime cannot execute the entrypoint binary or script |
| Privilege | Rootful examples as root; architecture and shebang behavior is the same rootless |
| Scope | Diagnosing exec format error from crun — host versus image Architecture, explicit --arch and --platform pulls, multi-architecture manifest inspection, missing shebang scripts, wrong interpreter paths, CRLF shebang lines, ENTRYPOINT and Cmd verification, and foreign-architecture binaries inside otherwise correct images. Does not cover multi-architecture image builds, QEMU installation, or general shell scripting. |
| Related guides | Write a Containerfile Build images with podman build |
Podman starts a container by asking crun to execute the image ENTRYPOINT or Cmd. When the Linux kernel cannot run that file, you get exec format error. That message sounds generic, but it almost always narrows to one of two causes: the binary targets the wrong CPU architecture for this host, or a text script is being executed directly without a shebang interpreter line.
ENTRYPOINT failure — missing files, permission bits, and exit codes belong in Fix container exits immediately. For building and publishing multi-architecture manifest lists, see Create multi-architecture images.
What exec format error means
These are the two failure shapes you will see most often on Podman 5.8.2 with crun. First, a text script executed without a shebang:
podman run --rm -v /tmp/exec-lab/run.sh:/run.sh:Z docker.io/library/alpine:3.20 /run.sh{"msg":"exec container process `/run.sh`: Exec format error","level":"error","time":"2026-08-23T09:42:02.230533Z"}Second, an ARM64 binary on an amd64 host:
podman run --rm localhost/podman-hello-arm64-test:latestWARNING: image platform (linux/arm64) does not match the expected platform (linux/amd64)
{"msg":"exec container process `/usr/local/bin/podman_hello_world`: Exec format error","level":"error","time":"2026-08-23T09:42:00.675583Z"}Podman 5.x may also surface a one-line wrapper such as Error: crun: executable file ...: Exec format error: OCI runtime error. The JSON msg and the crun wrapper describe the same kernel rejection — treat them as one symptom and split architecture mismatch from script interpreter problems before you rebuild the image.
Cause 1: image architecture does not match the host
The kernel executes native machine code for the host CPU. An arm64 ELF binary on an x86_64 host fails unless user-mode emulation is registered.
Check the host kernel architecture:
uname -mSample output on the lab machine:
x86_64Podman records the same value under a different label:
podman info --format '{{.Host.Arch}}'amd64x86_64 and amd64 name the same 64-bit Intel/AMD platform. Compare that to the image you are trying to run.
Check image architecture with podman image inspect
Replace IMAGE with your local tag or ID:
podman image inspect --format '{{.Architecture}}' IMAGEOn a healthy amd64 Alpine copy already on the lab host:
amd64When host and image disagree, you have an architecture mismatch even if the image pulled successfully:
host: amd64
image: arm64Storing a foreign-architecture image locally does not make it runnable. The failure appears at container start, not during podman pull.
Reproduce architecture mismatch on amd64
Docker Hub rate limits blocked docker.io/library/alpine:3.20 pulls during parts of this lab, so the mismatch demo uses quay.io/podman/hello:latest, which publishes both amd64 and arm64 entries.
Pull the ARM64 variant explicitly and give it a dedicated local name so you do not overwrite your working amd64 tags:
podman pull --arch arm64 quay.io/podman/hello:latestTag the foreign-architecture copy for testing:
podman tag quay.io/podman/hello:latest localhost/podman-hello-arm64-test:latestConfirm what you stored:
podman image inspect --format '{{.Architecture}}' localhost/podman-hello-arm64-test:latestarm64Run it on the amd64 host without QEMU user-static emulation (qemu-user-static is not installed on this lab machine, and binfmt_misc has no foreign-arch handlers):
podman run --rm localhost/podman-hello-arm64-test:latestWARNING: image platform (linux/arm64) does not match the expected platform (linux/amd64)
{"msg":"exec container process `/usr/local/bin/podman_hello_world`: Exec format error","level":"error","time":"2026-08-23T09:39:02.355892Z"}That is the architecture branch — not a broken ENTRYPOINT path.
Inspect a multi-architecture manifest
Official images often ship as a manifest list. Inspect the index before you blame Podman for picking the wrong platform:
podman manifest inspect quay.io/podman/hello:latestSample output (trimmed):
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
...
]
}Normally Podman selects the entry that matches the host. Problems appear when:
- you explicitly pulled
--arch arm64(or another foreign architecture) on the host CPU - a private tag contains only one foreign architecture
- CI built and pushed binaries for the wrong platform
Pull the correct architecture
Request the host-native platform explicitly:
podman pull --arch amd64 quay.io/podman/hello:latestPlatform syntax selects OS and architecture together:
podman pull --platform linux/amd64 quay.io/podman/hello:latestVerify before you run:
podman image inspect --format '{{.Architecture}}' quay.io/podman/hello:latestamd64A matching architecture should start cleanly:
podman run --rm quay.io/podman/hello:latestPodman prints the hello banner and exits 0 when the binary matches the host.
--arch versus --platform
Both flags choose which manifest entry Podman downloads. They do not convert binaries after the pull.
| Flag | Selects |
|---|---|
--arch arm64 |
CPU architecture entry |
--platform linux/arm64 |
OS and architecture pair (linux + arm64) |
Use --platform when you need to pin OS as well as CPU — for example linux/arm64 versus windows/amd64. Building manifest lists and publishing multi-architecture tags is covered in Create multi-architecture images.
QEMU and binfmt emulation
Cross-architecture execution can work when the host registers QEMU user emulators through binfmt_misc and packages such as qemu-user-static. On the RHEL 10.2 lab host used here:
qemu-user-staticis not installedbinfmt_miscexposes onlyregisterandstatus— noqemu-aarch64handler
This article reproduces the wrong-architecture failure honestly. It does not demonstrate a successful emulated arm64 run because that would require separately configured emulation outside this lab. If you need foreign architectures on amd64, plan native builders, CI on matching hardware, or install and register QEMU before expecting podman run to succeed.
Cause 2: script has no shebang
Linux executes scripts by reading the shebang (#!) interpreter on the first line. Without it, the kernel treats the file as a binary and rejects the text with exec format error.
Create a lab directory and write a script with no shebang:
mkdir -p /tmp/exec-labWrite the script body without a #! line:
printf 'echo "hello"\n' > /tmp/exec-lab/run.shMake it executable:
chmod +x /tmp/exec-lab/run.shRun the script directly as the container command:
podman run --rm -v /tmp/exec-lab/run.sh:/run.sh:Z docker.io/library/alpine:3.20 /run.sh{"msg":"exec container process `/run.sh`: Exec format error","level":"error","time":"2026-08-23T09:36:21.878701Z"}The mount path and chmod +x are correct — the missing interpreter line is the problem.
Fix the missing shebang
Add #!/bin/sh as the first line:
printf '#!/bin/sh\necho "hello"\n' > /tmp/exec-lab/run.shKeep the executable bit and rerun the same publish path:
chmod +x /tmp/exec-lab/run.shThe shebang line is in place now, so the same podman run path should print hello:
podman run --rm -v /tmp/exec-lab/run.sh:/run.sh:Z docker.io/library/alpine:3.20 /run.shhelloThe same script content with a shebang is valid. Rebuild or recopy the script into your image ENTRYPOINT when the failure happens at deploy time, not only on a bind mount.
Wrong shebang interpreter
A shebang pointing at a binary that does not exist in the image produces a different error — usually no such file or directory, not exec format error:
Recreate the lab directory and point the shebang at a path that does not exist:
mkdir -p /tmp/exec-labWrite a script that names a nonexistent interpreter:
printf '#!/bin/missing-interpreter\necho hello\n' > /tmp/exec-lab/run.shMark the script executable:
chmod +x /tmp/exec-lab/run.shRun it the same way as the no-shebang test:
podman run --rm -v /tmp/exec-lab/run.sh:/run.sh:Z docker.io/library/alpine:3.20 /run.sh{"msg":"exec container process (missing dynamic library?) `/run.sh`: No such file or directory","level":"error","time":"2026-08-23T09:41:04.363244Z"}A #!/bin/bash line on an image without Bash follows the same pattern. Alpine normally provides /bin/sh through BusyBox ash; /bin/bash is not present unless Bash was installed separately. Therefore a script with #!/bin/bash can fail with no such file or directory even though /bin/sh exists. Verify interpreters inside the image you ship:
podman run --rm docker.io/library/alpine:3.20 sh -c \
'ls -l /bin/sh; command -v bash || echo "bash not installed"'Typical output on Alpine 3.20:
lrwxrwxrwx 1 root root 12 Jan 26 2024 /bin/sh -> /bin/busybox
bash not installedDo not classify every ENTRYPOINT failure as exec format error when the transcript names a missing interpreter path.
Windows CRLF shebang lines
A shebang copied from Windows may embed a carriage return:
#!/bin/sh\rThat makes the kernel look for /bin/sh\r, which does not exist. The error is usually no such file or directory or a bad interpreter message — not always the literal exec format error string.
Inspect line endings on the host:
file run-crlf.shrun-crlf.sh: POSIX shell script, ASCII text executable, with CRLF line terminatorsfile flags CRLF terminators; sed -n l shows the hidden carriage returns:
sed -n l run-crlf.sh#!/bin/sh\r$
echo hello\r$Inside a container, mount the CRLF script and run it as the entry command:
podman run --rm -v /tmp/exec-lab/run-crlf.sh:/run.sh:Z docker.io/library/alpine:3.20 /run.sh{"msg":"exec container process (missing dynamic library?) `/run.sh`: No such file or directory","level":"error","time":"2026-08-23T09:36:27.797419Z"}Convert to Unix line endings (dos2unix, sed, or editor settings) before you bake the script into an image.
Check ENTRYPOINT and Cmd
When the architecture matches and the shebang looks correct, confirm what Podman is actually trying to execute:
podman image inspect --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}' IMAGEOn Alpine 3.20 in the lab:
null ["/bin/sh"]A null entrypoint with Cmd set means Podman runs /bin/sh when you start the Alpine image with no command override. For a failing named container, inspect the resolved process:
podman inspect CONTAINER --format '{{.Config.Entrypoint}} {{.Config.Cmd}}'Compare that path to files that exist in the image (podman run --rm IMAGE ls -l /path/to/binary).
Wrong-architecture binary inside a correct base image
The base image architecture can be amd64 while a single copied application binary targets arm64 — common after Go or Rust cross-compilation mistakes. The whole image inspect reports amd64, but one ENTRYPOINT binary still triggers exec format error.
Check the binary on the build host or extract it from the image:
file ./appExample output for a mismatched build artifact:
./app: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, ...Rebuild the application for the deployment architecture, or ship separate per-architecture images in a manifest list. Image-level Architecture metadata alone is not enough when you add foreign binaries in a later layer.
Diagnostic decision tree
exec format error
↓
uname -m and podman image inspect .Architecture
├─ mismatch → pull/build correct platform; emulation only if QEMU/binfmt configured
└─ same
↓
inspect ENTRYPOINT/Cmd
↓
text script executed directly?
├─ no shebang → add #!/bin/sh (or correct interpreter)
├─ CRLF shebang → convert to LF
├─ missing interpreter path → no such file (fix path or install binary)
└─ native binary → file(1) on binary; verify build archTroubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
exec format error right after podman run |
arm64 image on amd64 host (or reverse) |
podman pull --arch amd64 or --platform linux/amd64; build on native CPU |
WARNING: image platform ... does not match |
Foreign-architecture image on host | Pull host-native manifest entry |
exec format error on a .sh file |
No shebang | Add #!/bin/sh or invoke sh /path/script.sh |
no such file or directory on script |
Bad shebang path or CRLF | ls -l interpreter; file / dos2unix the script |
| Worked in CI, fails on laptop | Image built for CI CPU only | Inspect .Architecture; check manifest list |
Base amd64 but one binary fails |
Wrong-arch artifact copied in | file on binary; rebuild for target arch |
podman build --platform linux/arm64 RUN fails on amd64 |
No emulation during build | Native ARM builder or QEMU — see multi-arch guide |
References
- podman-image-inspect(1) — Podman documentation
- podman-pull(1) — Podman documentation
- podman-manifest-inspect(1) — Podman documentation
- crun manual
- Red Hat Enterprise Linux 10 — Building, running, and managing containers
Summary
exec format error means the Linux kernel refused to execute the file crun was asked to start. Split the problem into architecture mismatch versus script format before you rebuild unrelated layers. Compare uname -m and podman info host architecture to podman image inspect --format '{{.Architecture}}'. An explicit --arch arm64 pull on amd64 stores a valid image that still fails at podman run unless QEMU and binfmt_misc are configured — the lab reproduced that failure with quay.io/podman/hello and did not fake emulated success.
When architectures match, inspect ENTRYPOINT and Cmd, then read the target file. Text scripts executed without #!/bin/sh produce the same error string as a wrong CPU binary. Missing interpreters and CRLF shebangs usually surface as no such file or directory instead. A single foreign binary inside an otherwise amd64 image can still fail — use file on the artifact.
For manifest lists, --platform pulls, and assembly workflows, continue with Create multi-architecture images. For pull flags and registry behavior, see Pull images with podman pull.

