tursodatabase/turso · error · SystemExit

{path} is not an ELF file

Error message

{path} is not an ELF file

What it means

dynsym_names() reads the file and validates the ELF magic bytes (\x7fELF) before parsing. If the first 4 bytes do not match, the path does not point to an ELF binary (it may be a text file, Mach-O/PE binary, script, or empty file). The script exits with this message and status 1.

Source

Thrown at bindings/dotnet/scripts/check_elf_dynsym_exports.py:94

    name: int,
    typ: int,
    flags: int,
    offset: int,
    size: int,
    link: int,
    info: int,
    align: int,
    entsize: int,
) -> bytes:
    return struct.pack(
        "<IIQQQQIIQQ", name, typ, flags, 0, offset, size, link, info, align, entsize
    )


def dynsym_names(path: Path) -> set[str]:
    data = path.read_bytes()
    if data[:4] != b"\x7fELF":
        raise SystemExit(f"{path} is not an ELF file")

    layout = elf_layout(data, path)
    dynsym = find_dynsym(data, layout, path)
    return names_from_dynsym(data, layout, dynsym)


def elf_layout(data: bytes, path: Path) -> dict:
    endian = "<" if data[5] == 1 else ">"
    elf_class = data[4]
    if elf_class == 2:
        return {
            "endian": endian,
            "section_header_offset": struct.unpack_from(endian + "Q", data, 40)[0],
            "section_header_size": struct.unpack_from(endian + "H", data, 58)[0],
            "section_count": struct.unpack_from(endian + "H", data, 60)[0],
            "string_table_index": struct.unpack_from(endian + "H", data, 62)[0],
            "section_format": endian + "IIQQQQIIQQ",
            "symbol_format": endian + "IBBHQQ",

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Verify the file is the Linux ELF artifact: `file <path>` should report 'ELF 64-bit'
  2. Pass the correct .so path for the target platform; use platform-specific CI steps for .dll/.dylib
  3. Check the build actually succeeded and produced a real binary, not an empty/partial file
  4. If the file is genuinely an ELF but starts differently, check for corruption or accidental text wrapping

Example fix

// before
check_elf_dynsym_exports.py build/libturso.dylib turso_sync_database_new
// after
check_elf_dynsym_exports.py build/libturso.so turso_sync_database_new
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
path = Path(elf_path)
if not path.exists() or path.read_bytes()[:4] != b"\x7fELF":
    raise ValueError(f"{path} is not an ELF file")

Type guard

def is_elf(path) -> bool:
    try:
        return Path(path).read_bytes()[:4] == b"\x7fELF"
    except OSError:
        return False

Try / catch

try:
    subprocess.run(["check_elf_dynsym_exports.py", elf, *symbols], check=True)
except SystemExit:
    # or CalledProcessError when run via subprocess
    # verify with `file <elf>` that the artifact is a Linux ELF .so
    ...

Prevention

When it happens

Trigger: Calling missing_exports()/dynsym_names() on a path whose contents do not start with b'\x7fELF' — e.g. checking a .dll, .dylib, or an archive file instead of an ELF .so.

Common situations: CI passes the wrong platform artifact (Windows .dll or macOS .dylib on a Linux check step), the path points to a stub or a text file, the build failed and a placeholder file exists, or a glob picked up non-ELF files.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-09-13). Data as JSON: /api/errors/de945381e186ab14. Report an issue: GitHub.