oven-sh/bun · error · Error

InvalidPESignature

Error message

InvalidPESignature

What it means

The PE parser found a valid DOS header (MZ) but the 4-byte signature at the e_lfanew offset is not 'PE\0\0' (0x4550). Bun's standalone-compile pipeline for Windows targets parses the base executable byte-for-byte (PEFile::init, src/exe_format/pe.rs:272), and this check guards against truncated or non-PE binaries that merely start with MZ. It aborts the compile with 'Error initializing PE file: InvalidPESignature'.

Source

Thrown at src/exe_format/pe.rs:21

use core::mem::{offset_of, size_of};
use core::ptr;
use core::slice;

// New error types for PE manipulation
#[derive(thiserror::Error, strum::IntoStaticStr, Debug, Copy, Clone, Eq, PartialEq)]
pub enum Error {
    #[error("OutOfBounds")]
    OutOfBounds,
    #[error("BadAlignment")]
    BadAlignment,
    #[error("Overflow")]
    Overflow,
    #[error("InvalidPEFile")]
    InvalidPEFile,
    #[error("InvalidDOSSignature")]
    InvalidDOSSignature,
    #[error("InvalidPESignature")]
    InvalidPESignature,
    #[error("UnsupportedPEFormat")]
    UnsupportedPEFormat,
    #[error("InsufficientHeaderSpace")]
    InsufficientHeaderSpace,
    #[error("TooManySections")]
    TooManySections,
    #[error("SectionExists")]
    SectionExists,
    #[error("InputIsSigned")]
    InputIsSigned,
    #[error("InvalidSecurityDirectory")]
    InvalidSecurityDirectory,
    #[error("SecurityDirInsideImage")]
    SecurityDirInsideImage,
    #[error("UnexpectedOverlayPresent")]
    UnexpectedOverlayPresent,
    #[error("InsufficientSpace")]

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Re-download or rebuild the base bun.exe for the exact target (windows-x64 / windows-arm64) and retry the compile.
  2. If using a custom base executable, verify it runs on a Windows machine (or under Wine) before using it as the --compile base.
  3. Check the file is not truncated: compare its SHA-256 against the published checksum for that Bun release.
  4. Inspect the header manually: `xxd -l 2 base.exe` must show '4d 5a' (MZ) and the dword at offset e_lfanew (file offset 0x3c) must point at bytes '50 45 00 00'.

Example fix

# before: base exe came from an unverified cache
BUN_COMPILE_CACHE_DIR=./cache bun build app.ts --compile --target=windows-x64
# after: verify the base exe signature before compiling
xxd -s 0x3c -l 4 base.exe   # read e_lfanew, then check 'PE\0\0' there
bun build app.ts --compile --target=windows-x64  # with a fresh, verified bun.exe
Defensive patterns

Strategy: validation

Validate before calling

// Run before `bun build --compile --base base.exe`
const bytes = await Bun.file('base.exe').arrayBuffer();
const dv = new DataView(bytes);
function isPE64(buf, dv) {
  if (buf.byteLength < 0x40 || dv.getUint16(0, true) !== 0x5a4d) return false; // 'MZ'
  const peOff = dv.getUint32(0x3c, true);
  if (peOff + 4 > buf.byteLength) return false;
  return dv.getUint32(peOff, true) === 0x00004550; // 'PE\0\0'
}
if (!isPE64(bytes, dv)) throw new Error('base.exe is not a valid PE image');

Prevention

When it happens

Trigger: Running `bun build --compile --target=windows` (or on a Windows host) where the base executable (the copied Bun binary passed via `--compile`'s base, i.e. the runtime executable being extended) is corrupted mid-copy, was byte-patched, is truncated by a partial download/clone with git LFS, or is actually a DOS/other binary that happens to begin with 'MZ'. Thrown from PEFile::init at src/exe_format/pe.rs:272-274 when pe_header.signature != 0x00004550.

Common situations: A custom base executable (`--bytecode`/base exe workflows, BUN_COMPILE_CACHE or copied bun.exe) that got corrupted; CI caches storing a truncated exe; antivirus quarantining/altering bun.exe; using a Git-LFS pointer file or HTML error page saved as .exe as the base.

Related errors


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