oven-sh/bun · error · bun_exe_format::pe::Error

UnsupportedPEFormat

Error message

UnsupportedPEFormat

What it means

The optional header magic is not 0x020B (PE32+/64-bit), so Bun refuses the image (src/exe_format/pe.rs:291-293). Bun's .bun-section injector only understands 64-bit PE images because the injected section layout (OptionalHeader64, 16 data directories) assumes PE32+. A 32-bit PE has magic 0x010B and a different optional-header shape, so parsing on would be unsound.

Source

Thrown at src/exe_format/pe.rs:23

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")]
    InsufficientSpace,
}

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Use the 64-bit Bun executable as the base (bun-windows-x64 / bun-windows-aarch64); Bun ships only PE32+ binaries.
  2. Verify the base with `file base.exe` — it must report 'PE32+ executable', not 'PE32 executable'.
  3. Clear stale build caches (BUN_COMPILE_CACHE) that may hold a 32-bit base from earlier experiments.
  4. If you must target 32-bit Windows, that is unsupported by `bun build --compile`; ship the 64-bit binary instead.

Example fix

# before
file base.exe   # 'PE32 executable (console) Intel 80386'
bun build app.ts --compile --target=windows-x64 --base base.exe
# after: fetch the matching 64-bit base
file bun.exe    # 'PE32+ executable (console) x86-64'
bun build app.ts --compile --target=windows-x64
Defensive patterns

Strategy: validation

Validate before calling

const bytes = await Bun.file('base.exe').arrayBuffer();
const dv = new DataView(bytes);
const peOff = dv.getUint32(0x3c, true);
const optMagicOff = peOff + 4 + 20; // signature + COFF header
if (dv.byteLength < optMagicOff + 2 || dv.getUint16(optMagicOff, true) !== 0x020b) {
  throw new Error('base.exe is not PE32+ (64-bit) — get the x64/arm64 Bun build');
}

Prevention

When it happens

Trigger: `bun build --compile` targeting Windows with a 32-bit (i386) base executable, e.g. a manually supplied 32-bit bun build, an old 32-bit launcher used as the base, or any PE32 image. Thrown when optional_header.magic != 0x020B in PEFile::init.

Common situations: Mixing architectures: building with a windows-x64 target while the base exe on PATH or in the cache is 32-bit; legacy toolchains producing PE32 wrappers; using a 32-bit stub loader as the custom base for Bun compilation.

Related errors


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