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

UnexpectedOverlayPresent

Error message

UnexpectedOverlayPresent

What it means

After removing the certificate table, bytes still remain beyond the last section's raw-data end (src/exe_format/pe.rs:422-426). Those trailing bytes are an 'overlay' (debug data, appended archives, a second signature) that strip_authenticode did not account for; the injector refuses to proceed because the overlay's meaning is unknown.

Source

Thrown at src/exe_format/pe.rs:37

    #[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,
}

/// Windows PE Binary manipulation for codesigning standalone executables
pub struct PEFile {
    pub(crate) data: Vec<u8>,
    // Store offsets instead of pointers to avoid invalidation after resize
    pub(crate) pe_header_offset: usize,
    pub(crate) optional_header_offset: usize,
    pub(crate) section_headers_offset: usize,
    pub(crate) num_sections: u16,
}

// PE/COFF on-disk header structs are byte-packed (no padding) per spec, and may
// live at arbitrary byte offsets inside a `Vec<u8>` image, so `align_of` must be 1
// for it to be sound to materialize references/pointers to them from the buffer.

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Use the plain Bun executable as the base — it has no overlay.
  2. Strip the overlay from the custom base: truncate the file to max(section PointerToRawData+SizeOfRawData) with a small script, or use a PE overlay remover tool, then compile.
  3. Confirm with `pefile` (Python) or `dumpbin` that Overlay offset/size are zero after cleaning.
  4. Re-sign the final output (`signtool sign`) after Bun compiles it — signing last avoids the strip path entirely.

Example fix

# before: base has appended overlay -> UnexpectedOverlayPresent
bun build app.ts --compile --base sfx-stub.exe --target=windows-x64
# after: truncate overlay, then compile (and re-sign after)
python -c "import pefile,os; p=pefile.PE('sfx-stub.exe', fast_load=True); end=max(s.PointerToRawData+s.SizeOfRawData for s in p.sections); os.truncate('clean.exe' if False else 'sfx-stub.exe', end)"
bun build app.ts --compile --base sfx-stub.exe --target=windows-x64
Defensive patterns

Strategy: fallback

Validate before calling

python -c "
import pefile
pe = pefile.PE('base.exe')
last = max((s.PointerToRawData + s.SizeOfRawData) for s in pe.sections)
assert len(pe.__data__) <= last or (pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].VirtualAddress == last), 'unexpected overlay present'
"

Prevention

When it happens

Trigger: `bun build --compile --target=windows` where the base exe has data appended after the last section in addition to (or instead of) the certificate table — e.g. self-extracting installer stubs, bootstrappers that append a ZIP, or PEs with detached debug-directory file content.

Common situations: Using installer/SFX stubs or packer output as the compile base; executables with appended .NET native payloads or embedded ZIPs; CI bases processed by tools that append metadata blobs.

Related errors


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