t8y2/dbx · error · PeFormatError

missing DOS header

Error message

missing DOS header

What it means

PeFormatError raised by imported_dlls when the file is shorter than 64 bytes or does not start with the b"MZ" DOS magic. Every Windows PE must begin with an MZ DOS stub containing at least a 64-byte header that holds the PE-offset pointer at 0x3C; without it the file is not a PE and cannot be parsed at all.

Source

Thrown at agents/scripts/validate_windows_pe_dependencies.py:39

    return struct.unpack_from("<I", data, offset)[0]


def _read_c_string(data: bytes, offset: int) -> str:
    if offset < 0 or offset >= len(data):
        raise PeFormatError("PE string offset is outside the file")
    end = data.find(b"\0", offset)
    if end < 0:
        raise PeFormatError("unterminated PE string")
    try:
        return data[offset:end].decode("ascii")
    except UnicodeDecodeError as error:
        raise PeFormatError("PE import name is not ASCII") from error


def imported_dlls(path: Path) -> list[str]:
    data = path.read_bytes()
    if len(data) < 64 or data[:2] != b"MZ":
        raise PeFormatError("missing DOS header")

    pe_offset = _read_u32(data, 0x3C)
    if data[pe_offset : pe_offset + 4] != b"PE\0\0":
        raise PeFormatError("missing PE signature")

    section_count = _read_u16(data, pe_offset + 6)
    optional_header_size = _read_u16(data, pe_offset + 20)
    optional_header_offset = pe_offset + 24
    optional_magic = _read_u16(data, optional_header_offset)
    if optional_magic == 0x20B:
        data_directories_offset = optional_header_offset + 112
    elif optional_magic == 0x10B:
        data_directories_offset = optional_header_offset + 96
    else:
        raise PeFormatError(f"unsupported PE optional header magic: 0x{optional_magic:04x}")

    import_directory_rva = _read_u32(data, data_directories_offset + 8)
    import_directory_size = _read_u32(data, data_directories_offset + 12)

View on GitHub (pinned to c0390bff16)

Solutions

  1. Check that the path points to an actual Windows PE (.exe/.dll/.sys) built for Windows; verify first bytes are 'MZ' (e.g. `head -c2 file`).
  2. Fix the build/CI artifact path — the file is likely a Linux binary or an empty/failed build output.
  3. Catch PeFormatError around imported_dlls and report 'not a Windows PE' to the user.
  4. If the file should be a PE, rebuild it; a 0–63 byte file means the build or download failed.

Example fix

# before
imports = imported_dlls(Path(args.file))
# after
if not args.file.is_file() or args.file.read_bytes()[:2] != b"MZ":
    raise SystemExit(f"{args.file} is not a Windows PE")
imports = imported_dlls(args.file)
Defensive patterns

Strategy: validation

Validate before calling

def ensure_pe_file(path: Path) -> None:
    if not path.is_file():
        raise SystemExit(f"{path}: not a file")
    data = path.read_bytes()
    if len(data) < 64 or data[:2] != b"MZ":
        raise SystemExit(f"{path}: not a Windows PE (missing MZ header)")

Type guard

def is_pe_candidate(path: Path) -> bool:
    try:
        with path.open("rb") as f:
            return f.read(2) == b"MZ" and path.stat().st_size >= 64
    except OSError:
        return False

Try / catch

try:
    imports = imported_dlls(path)
except PeFormatError as error:
    if "missing DOS header" in str(error):
        print(f"{path} is not a Windows PE; check the artifact path")
    else:
        raise

Prevention

When it happens

Trigger: Calling imported_dlls(path) (directly or via main / the validator CLI) on: a text file, an ELF/Mach-O binary, an empty or near-empty file, a script, or any file whose first two bytes are not 'MZ'.

Common situations: Pointing the validator at the wrong build artifact (e.g. a Linux .so in cross-platform CI), passing a source file or config instead of a compiled exe, running on a zero-byte placeholder created by a failed build, or validating a renamed non-Windows binary.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/46dd07faca43f39e. Report an issue: GitHub.