What just happened
You downloaded a binary, compiled a program, or copied an executable from another machine โ then ran it and got this:
bash: ./app: cannot execute binary file: Exec format error
The shell found the file. It confirmed the execute bit is set. But the kernel flat-out refused to run it. That refusal almost always points to one of three things: the binary targets a different CPU architecture, the file isn't actually an executable, or the ELF interpreter is missing. Each cause needs a different fix. Skip the diagnosis and you'll spend twenty minutes on the wrong one.
Step 1 โ Check what the file actually is
Run file on the binary. It's the fastest way to see what architecture and format it was built for:
file ./app
Example outputs and what they mean:
# ARM binary on an x86_64 machine โ architecture mismatch
./app: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
# x86_64 binary โ should run on most modern Linux machines
./app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV)
# Not an ELF at all โ maybe a Windows .exe someone renamed
./app: PE32+ executable (console) x86-64, for MS Windows
# Shell script without shebang
./app: ASCII text
Now check your own machine's architecture:
uname -m
# x86_64 โ Intel/AMD 64-bit
# aarch64 โ ARM 64-bit (Apple Silicon, Raspberry Pi 4, AWS Graviton)
# armv7l โ ARM 32-bit (older Raspberry Pi)
Mismatch between file output and uname -m? That's your culprit.
Step 2 โ Identify the exact cause
Cause A: Architecture mismatch (most common)
You're running an ARM binary on an x86_64 machine, or the other way around. Four situations trigger this reliably:
- You pulled a pre-built binary from the internet without checking the architecture label
- You built on an Apple Silicon Mac (aarch64) and copied the binary to an x86_64 server
- You're inside a Docker container whose base image targets a different architecture than the host
- You cross-compiled but didn't set the target correctly
Cause B: Wrong file format (not an ELF)
Windows PE executables (.exe), macOS Mach-O binaries, and plain text scripts without a shebang line all produce the same error. The file extension doesn't matter โ Linux uses magic bytes, not the name.
Cause C: 32-bit binary on a 64-bit system without 32-bit libs
Even a matching-architecture binary can fail here. A 32-bit x86 ELF on a 64-bit Linux system needs the lib32 packages installed:
file ./app
# ./app: ELF 32-bit LSB executable, Intel 80386
Step 3 โ Apply the right fix
Fix A: Get the correct binary for your architecture
Downloading a pre-built release? Grab the right archive for your platform. Most projects use predictable naming:
# x86_64 / amd64
app-linux-amd64
app-linux-x86_64
# ARM 64-bit
app-linux-arm64
app-linux-aarch64
# ARM 32-bit
app-linux-armv7
app-linux-arm
Download, verify with file, then run:
curl -LO https://example.com/releases/app-linux-amd64
chmod +x app-linux-amd64
file ./app-linux-amd64
./app-linux-amd64
Fix B: Recompile for the target architecture
Got source code? Compile directly on the target machine, or cross-compile with the right target flag.
Go makes cross-compilation trivial โ two environment variables are all you need:
# Compile for Linux x86_64
GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
# Compile for Linux ARM64
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
For C with GCC, install a cross-compiler toolchain first:
# Install ARM cross-compiler
sudo apt install gcc-aarch64-linux-gnu
# Compile for ARM64
aarch64-linux-gnu-gcc -o app-arm64 main.c
Fix C: Add QEMU emulation (run foreign binaries without recompiling)
Sometimes you can't recompile โ the binary is closed-source, or you just need a quick test. QEMU user-mode emulation lets you run foreign-arch binaries without touching any source:
# Install QEMU user-mode emulation
sudo apt install qemu-user qemu-user-static
# Run an ARM64 binary on x86_64
qemu-aarch64 ./app-arm64
# Register binfmt_misc handlers so the kernel invokes QEMU automatically
sudo apt install binfmt-support
sudo update-binfmts --enable qemu-aarch64
Once the binfmt handlers are registered, you don't need the prefix anymore:
./app-arm64 # runs transparently via QEMU
Fix D: Install 32-bit support for 32-bit ELF binaries
# Debian/Ubuntu
sudo apt install lib32z1 lib32stdc++6
# CentOS/RHEL
sudo yum install glibc.i686 libstdc++.i686
Fix E: Add a shebang if it's a script
Plain text output from file means the file is missing its interpreter line. Check the first line:
head -1 ./app
No #! at the top? Add one:
#!/usr/bin/env bash
# rest of your script...
Then re-set the execute bit and run:
chmod +x ./app
./app
Docker-specific scenario
Docker containers are where this error ambushes people most. Pulling an arm64 image on an x86_64 host โ or building on an M1 Mac and deploying to a cloud VM โ silently produces the wrong architecture. Check before you ship:
# Check your image's architecture
docker inspect --format='{{.Architecture}}' myimage
# Pull a specific platform explicitly
docker pull --platform linux/amd64 myimage
# Build for a specific platform
docker buildx build --platform linux/amd64 -t myimage .
Deploying to ARM servers like AWS Graviton or Raspberry Pi? Set --platform linux/arm64 in your build step and make it part of your CI pipeline, not an afterthought.
Verify the fix worked
# 1. Confirm architecture matches your machine
file ./app
uname -m
# 2. Run the binary
./app
# 3. Check exit code โ 0 means success
echo $?
Still failing after fixing the architecture? Missing shared libraries are the next suspect:
ldd ./app
# Look for lines like:
# libssl.so.1.1 => not found
Each not found entry maps to a package you need to install.
Quick reference
- Architecture mismatch โ download the correct binary or recompile for the target arch
- Need to run a foreign-arch binary โ install QEMU user-mode + binfmt_misc
- 32-bit binary on 64-bit system โ install
lib32packages - Script without shebang โ add
#!/usr/bin/env bashas the first line - Windows/macOS binary โ you need the Linux build, full stop
Run file ./app first. Always. Two seconds of output tells you exactly which of these five fixes applies.

