oven-sh/bun · error · ElfError

InvalidElfFile

InvalidElfFile

Error message

InvalidElfFile

What it means

ElfError::InvalidElfFile comes from Bun's own ELF writer (src/exe_format/elf.rs) used by `bun build --compile` (via StandaloneModuleGraph) when appending the embedded module graph to a Linux executable. It fires when the input binary is shorter than an ELF64 header, lacks the \x7fELF magic, or has section-header/shstrtab/RW-segment offsets beyond end-of-file — i.e. the file is not a valid ELF64 or is truncated/corrupted.

Source

Thrown at src/exe_format/elf.rs:23

//! and expands it to hold the standalone module graph data.
//!
//! Must work on any host platform (macOS, Windows, Linux) for cross-compilation.

use core::mem::size_of;
#[cfg(any(target_os = "linux", target_os = "android"))]
use core::sync::atomic::{AtomicU8, Ordering};

#[cfg(any(target_os = "linux", target_os = "android"))]
use bun_core::env_var;
use bun_core::{slice_to_nul, strings};

use crate::{align_up, read_struct, write_struct};

bun_core::declare_scope!(elf, visible);

#[derive(Debug, thiserror::Error, strum::IntoStaticStr)]
pub enum ElfError {
    #[error("InvalidElfFile")]
    InvalidElfFile,
    #[error("Not64Bit")]
    Not64Bit,
    #[error("NotLittleEndian")]
    NotLittleEndian,
    #[error("BunSectionNotFound")]
    BunSectionNotFound,
    #[error("NoWritableLoadSegment")]
    NoWritableLoadSegment,
    #[error("NewVaddrCollides")]
    NewVaddrCollides,
}

pub struct ElfFile {
    pub data: Vec<u8>,
}

impl ElfFile {

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Verify the base binary with `file ./bun` (must say ELF 64-bit LSB) and rebuild/redownload it if truncated.
  2. Make sure the --compile target triple matches the binary's actual format (use a linux target for ELF patching).
  3. Re-run the failing build after removing corrupted artifacts; check dmesg/disk if truncation repeats.

Example fix

# before: host binary is not the ELF being patched
bun build --compile --target=darwin-arm64 ./app.ts  # then patching path given an ELF

# after: match formats
file ./build/debug/bun-debug  # expect: ELF 64-bit LSB ...
bun build --compile --target=linux-arm64 ./app.ts
Defensive patterns

Strategy: try-catch

Validate before calling

fn is_elf64_le(data: &[u8]) -> bool {
    data.len() >= size_of::<Elf64_Ehdr>() && &data[0..4] == b"\x7fELF"
}
// before patching:
if !is_elf64_le(&template_bytes) {
    return Err(format!("template is not ELF64: {}", template_path.display()));
}

Type guard

fn is_elf64_le(data: &[u8]) -> bool {
    data.len() >= 64 && data[..4] == *b"\x7fELF" && data[4] == 2 /* ELFCLASS64 */ && data[5] == 1 /* ELFDATA2LSB */
}

Try / catch

match bun_elf::Elf64::from_bytes(template) {
    Ok(mut elf) => elf.add_section(payload)?,
    Err(ElfError::InvalidElfFile) => {
        return Err(format!("not a valid ELF64 binary (truncated or wrong format): {}", path.display()));
    }
    Err(ElfError::Not64Bit | ElfError::NotLittleEndian) => return Err("wrong ELF class or endianness".into()),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Compiling a standalone executable where the ELF template is a Mach-O/PE binary (wrong --target for the host file), a partially copied/truncated bun binary, or a corrupted build artifact with out-of-bounds e_shoff/shstrtab offsets.

Common situations: Cross-compiling with a mismatched --target triple; a base executable corrupted in transfer or by post-processing tools (upx, signers, buggy strip); disk-full during a previous build leaving a truncated binary.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/35307a45431911fb. Report an issue: GitHub.