A download page says 32-bit, the file lands on a Raspberry Pi, and the installer fails with a message that names no useful part of the problem. Two entirely different executables both count as 32-bit in the ELF sense, and only one of them can run on that board. The class field is one fact, the machine field is another, and a filename reliably tells you neither. Read the header before changing a library or trying another mirror.

Class says word size, machine says instruction set

The Linux ELF reference defines a class field and a machine field in the file header, and the two answer different questions. Class says whether the file uses 32-bit or 64-bit form; machine says which instruction set it was built for. A 32-bit x86 build and a 32-bit ARM build agree on the first and disagree on the second. That is how a label promising the right word size still delivers code the processor cannot decode. The third value worth reading is the requested interpreter, which the program headers name when the binary declares one.

readelf -h -- ./vendor-vpn
readelf -l -- ./vendor-vpn
readelf -d -- ./vendor-vpn | grep NEEDED

The first command prints the header, the second prints program headers when the file has any, and the third lists the shared objects the loader will need. Record class, machine and interpreter together, because those three values are the entire compatibility question at this layer. None of the three appears on a download button, which is why the file has to be inspected rather than described.

What interpreter it asks the kernel for

An executable that declares an interpreter asks the kernel for one specific loader path. When that loader is absent, the launch fails even though the file you named is sitting right there. That is the point where people decide the download is corrupt, when the actual answer is a loader the distribution does not ship.

Match the loader to the system you actually run: the OS release, the userspace architecture, and the package that provides the loader. A 64-bit kernel can run a 32-bit userspace only when that userspace and its loader are installed, so the processor's abilities are not the deciding factor. One short check names the interpreter on a single line, and it takes less time than a support ticket. A shell script fails differently again, because its interpreter is named on the first line rather than in an ELF header, and reading that line costs nothing.

file --brief ./vendor-vpn

Match the download to the package architecture

Distribution package architectures encode the same distinction in their own vocabulary, and that vocabulary is what a vendor's support statement refers to. Compare the value your package manager reports with the value the vendor documents, instead of comparing a marketing label against a filename. The pairs that cause trouble are amd64 against arm64, and armhf against armel, because each pair looks interchangeable in a download list. A filename ending in x64 or ia32 describes a build target, not the machine holding it.

Label on the downloadELF classe_machineInterpreter the kernel wantsHow it fails on the wrong host
amd64ELF64x86-64/lib64/ld-linux-x86-64.so.2Immediate exec failure on an ARM board
armhfELF32ARM/lib/ld-linux-armhf.so.3Loads on a soft-float system, then fails on a float ABI call
i386ELF32Intel 80386/lib/ld-linux.so.2Exec format error where no 32-bit loader package exists

Every row is a case where the word size looks right and the code still misbehaves, or where it starts and then fails one layer down. Read the interpreter column as a hard requirement rather than a hint, because the kernel resolves that path before any of your code executes. Emulation is a deployment decision with its own performance and support consequences, and it is never implied by a processor advertising a wider word size.

dpkg --print-architecture

ENOEXEC and ENOENT are different failures

The launch stage reports one of two errors, and they point at different problems. Reading the error value classifies the failure before you run anything else.

ENOEXEC means the format was not recognised: wrong architecture, wrong class, or something that is not an executable at all. ENOENT on an ELF file usually means the interpreter is missing, even though the file you asked for exists. The same ENOENT can also mean a script's interpreter is absent, which is why the first line of a script matters. Either way the message names the layer, and treating every not-found as a missing configuration sends the investigation in the wrong direction. Quote the error value in the ticket, because it survives retelling better than the sentence around it.

What not to do when the binary will not start

Forcing an unexplained binary through a shell wrapper does not make it run. Do not run a dependency checker casually on a file you do not trust, because running it can execute code from the binary in some circumstances. Do not add loader symlinks, swap host libraries or fetch an old archive from a third-party mirror to get past the message. Each of those widens the change surface without touching the mismatch the header already named.

When you approach the vendor, send values rather than a story: the OS release, the package architecture, the class and machine strings, the requested interpreter and the first error line. That set resolves support questions faster than a screenshot of a failing installer. Old artifacts and remembered forum output are not a current support matrix, and once a native binary loads, profile, authentication and routing remain separate work.

Nuŋlɔɖi siwo ku ɖe eŋu