Short answer
ldd reads the dynamic section of an ELF file. A statically linked binary has none,
so ldd reports not a dynamic executable and exits 1. The binary is not broken.
It simply does not need a loader at runtime.
This is the most common false alarm in Linux binary troubleshooting: people read it as
"the executable is invalid" and start looking for a missing library that does not exist.
Confirm it in three commands
Take any static binary — a Go or Rust build, or busybox from a static image — and run:
$ ldd ./hello-static not a dynamic executable $ echo $? 1 $ file ./hello-static ./hello-static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=rLXBd7VvG-TozsbigJ3a/..., stripped $ readelf -d ./hello-static There is no dynamic section in this file. file says statically linked and readelf -d says no dynamic section. Both agree
with ldd. Nothing is missing.
What the message actually means
| Tool | Says | Because |
|---|---|---|
ldd | not a dynamic executable | no DT_NEEDED, no PT_INTERP |
file | statically linked | same reason, different wording |
readelf -d | There is no dynamic section in this file. | the .dynamic section is absent |
| `readelf -l \ | grep -c INTERP` | 0 |
Contrast with a dynamically linked binary on the same host:
$ readelf -l ./hello-new | grep -A1 INTERP INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318 $ readelf -d ./hello-new | grep NEEDED 0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6] 0x0000000000000001 (NEEDED) Shared library: [libm.so.6] 0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] An INTERP entry plus a list of NEEDED libraries is what ldd needs to do its job.
A static binary has neither.
Where this shows up in practice
Go and Rust builds. CGO_ENABLED=0 Go builds and musl-targeted Rust builds are static
by default. Running ldd on them is a category error, not a defect.
Distroless and scratch images. There is no shell, no binutils, sometimes no ldd.
Static busybox. busybox --install links applets into a single static binary; every
applet reports this message.
Jump hosts without binutils. A slim debian:12 image has neither file nor readelf:
$ file ./hello-static sh: 1: file: not found $ readelf -h ./hello-static sh: 1: readelf: not found That is exactly the situation the ELF Inspector exists for — it
parses in your browser, so the target host needs no tooling and the binary is not uploaded.
When not a dynamic executable is a real problem
Rarely, but it matters:
- You expected a dynamic binary. If a build system silently produced a static binary,
dlopen()will fail at runtime because there is no dynamic loader in the process. - glibc NSS breaks. A fully static glibc binary cannot load NSS modules (
getpwnam, DNS viagetaddrinfocan behave oddly). Use-staticwith care, or prefer static musl. - The binary was corrupted mid-transfer. Combined with a truncated file,
lddcan also report this. Check the size and a checksum if the file came over the network.
In every other case the message is informational.
What to use instead
# what kind of file is it at all file ./binary # architecture, word size, endianness, type readelf -h ./binary | head -20 # any dynamic dependencies (empty output = static) readelf -d ./binary | grep NEEDED # interpreter present? readelf -l ./binary | grep INTERP # the same information without installing binutils # -> open the binary in the browser ELF Inspector The browser tool reports the same fields and adds the verdicts that are easy to get wrong
by hand: PIE, static vs shared object, full RELRO, stripped, and the required
GLIBC_* / GLIBCXX_* symbol versions.
One safety note about ldd
For dynamically linked binaries, ldd is not a pure reader. Most implementations
execute the program's own loader (LD_TRACE_LOADED_OBJECTS) to get the resolution result.
On an untrusted binary that means running its interpreter.
Static binaries are not affected — that is the one case where ldd genuinely cannot
execute anything. For untrusted files, prefer readelf -d or the browser tool, which only
parse data.
FAQ
Does not a dynamic executable mean the binary is corrupted? No. It means there is no
dynamic section to inspect. A corrupted file usually gives a different error
(cannot execute binary file, invalid ELF header).
Why does ldd exit 1 then? Because it could not perform the requested inspection.
Exit status reflects the tool's success, not the binary's validity.
How do I know whether a binary is static or dynamic without ldd? file prints
statically linked or dynamically linked; readelf -d prints the dynamic section or
says there is none.
Can a static binary still fail at runtime? Yes — on a kernel that does not support its
architecture, on a filesystem mounted noexec, or when it needs files it expects to find
(glibc static + NSS). Those are different errors than this one.
