github/copilot-sdk · error · IOException

Not an ELF executable

Error message

Not an ELF executable

What it means

readElfPtInterp checks the first 4 bytes of the probe against the ELF magic number (0x7F 'E' 'L' 'F'). If they do not match, the file is not an ELF executable and PT_INTERP parsing cannot proceed, so an IOException is thrown. This guards against parsing arbitrary non-ELF files.

Solutions

  1. Confirm the target file is actually ELF: run file <path>; expect 'ELF 64-bit LSB ...'.
  2. Only invoke ELF parsing on Linux targets; use the platform-appropriate path (Mach-O/PE) on macOS/Windows.
  3. Re-download or reinstall the binary — an HTML error page or truncated file has no ELF magic.
  4. Check that symlinks resolve to the real binary and not a script.

Example fix

// before
String interp = readElfPtInterp(probe); // probe from wrapper.sh
// after
byte[] probe = readHead(binaryPath);
if ((probe[0] & 0xFF) != 0x7F || probe[1] != 'E' || probe[2] != 'L' || probe[3] != 'F') {
    throw new IOException(binaryPath + " is not an ELF binary; path=" + binaryPath);
}
String interp = readElfPtInterp(probe);
Defensive patterns

Strategy: try-catch

Validate before calling

byte[] magic = new byte[4];
try (InputStream in = Files.newInputStream(path)) { in.readNBytes(magic, 0, 4); }
if (magic[0] != 0x7F || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') {
    throw new IOException(path + " is not an ELF binary");
}

Type guard

static boolean isElf(Path p) throws IOException {
    byte[] m = new byte[4];
    try (InputStream in = Files.newInputStream(p)) { return in.readNBytes(m, 0, 4) == 4
        && m[0] == 0x7F && m[1] == 'E' && m[2] == 'L' && m[3] == 'F'; }
}

Try / catch

try {
    String interp = resolveInterpreter(binaryPath);
} catch (IOException e) {
    if (e.getMessage().contains("Not an ELF")) {
        throw new IllegalStateException(binaryPath + " is not an ELF executable (wrong platform or wrapper script)", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: The probe comes from a file that is not an ELF binary: a Mach-O binary (macOS), a PE binary (Windows), a shell script, a text file, or a truncated/corrupt download whose magic bytes were lost.

Common situations: Running interpreter resolution on macOS or Windows binaries when the code path assumes ELF; pointing the resolver at a wrapper script; downloading a binary over a connection that served an HTML error page instead of the file.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/8860fca4afefd9e9. Report an issue: GitHub.

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/ffi/PlatformDetector.java:170

        if (classifier == null || !SUPPORTED_CLASSIFIERS.contains(classifier)) {
            throw new IllegalStateException(
                    "Unsupported platform tuple: os=" + os + ", arch=" + arch + ", libc=" + classifierLibc);
        }
        return classifier;
    }

    static Set<String> supportedClassifiers() {
        return SUPPORTED_CLASSIFIERS;
    }

    private static String readElfPtInterp(byte[] probe) throws IOException {
        int size = probe.length;
        if (size < 64) {
            throw new IOException("ELF probe too small: " + size + " bytes");
        }
        if ((probe[0] & 0xFF) != ELF_MAGIC_0 || (probe[1] & 0xFF) != ELF_MAGIC_1 || (probe[2] & 0xFF) != ELF_MAGIC_2
                || (probe[3] & 0xFF) != ELF_MAGIC_3) {
            throw new IOException("Not an ELF executable");
        }

        int elfClass = probe[4] & 0xFF;
        int elfData = probe[5] & 0xFF;
        if (elfData != ELF_DATA_LITTLE_ENDIAN && elfData != ELF_DATA_BIG_ENDIAN) {
            throw new IOException("Unsupported ELF data encoding: " + elfData);
        }
        boolean littleEndian = elfData == ELF_DATA_LITTLE_ENDIAN;

        long phoff;
        int phentsize;
        int phnum;
        int minimumPhentsize;
        if (elfClass == ELF_CLASS_64) {
            phoff = readUInt64(probe, 32, littleEndian);
            phentsize = readUInt16(probe, 54, littleEndian);
            phnum = readUInt16(probe, 56, littleEndian);
            minimumPhentsize = ELF64_PROGRAM_HEADER_SIZE;

View on GitHub (pinned to cd8cf15dc3)