jdx/mise · error · eyre::Report
local mise is not an ELF executable
Error message
local mise is not an ELF executable
What it means
Thrown by elf_interpreter when the bytes of the binary being validated for a Linux remote do not start with the \x7fELF magic. validate_default_binary_compatibility only runs for Linux-to-Linux uploads, so a non-ELF payload means the configured mise_bin is not a Linux executable — e.g. a shell wrapper script, a macOS Mach-O copied over, or a truncated/corrupted file.
Source
Thrown at src/system/remote.rs:1358
}
let component = std::str::from_utf8(&bytes[start..offset])
.ok()?
.parse()
.ok()?;
components.push(component);
if bytes.get(offset) != Some(&b'.') {
break;
}
offset += 1;
}
(!components.is_empty()).then_some(AbiVersion(components))
}
fn elf_interpreter(bytes: &[u8]) -> Result<Option<String>> {
const ELF_MAGIC: &[u8] = b"\x7fELF";
const PT_INTERP: u64 = 3;
if !bytes.starts_with(ELF_MAGIC) {
bail!("local mise is not an ELF executable");
}
let class = *bytes.get(4).ok_or_else(|| eyre!("truncated ELF header"))?;
let little_endian = match bytes.get(5) {
Some(1) => true,
Some(2) => false,
_ => bail!("unsupported ELF byte order"),
};
let (program_offset, entry_size, entry_count, offset_field, size_field) = match class {
1 => (
read_elf_int(bytes, 28, 4, little_endian)?,
read_elf_int(bytes, 42, 2, little_endian)?,
read_elf_int(bytes, 44, 2, little_endian)?,
4,
16,
),
2 => (
read_elf_int(bytes, 32, 8, little_endian)?,
read_elf_int(bytes, 54, 2, little_endian)?,View on GitHub (pinned to 6f52dcdf99)
Solutions
- Point mise_bin at a real Linux ELF executable (file mise should say ELF 64-bit ... for Linux)
- Re-download or rebuild the binary if it is truncated (compare size/checksum)
- Remove script wrappers from the upload path; put env setup in mise_env or the remote config instead
Example fix
# before (mise.toml) [bootstrap.remote.hosts.srv] host = "deploy@srv" mise_bin = "./mise-wrapper.sh" # after [bootstrap.remote.hosts.srv] host = "deploy@srv" mise_bin = "./mise" # file ./mise -> ELF 64-bit LSB executable, x86-64
Defensive patterns
Strategy: validation
Validate before calling
// Validate the binary before pointing mise_bin at it (Linux remotes)
fn is_linux_elf(path: &Path) -> bool {
let mut magic = [0u8; 6];
let Ok(mut f) = std::fs::File::open(path) else { return false };
std::io::Read::read_exact(&mut f, &mut magic).is_ok()
&& &magic[..4] == b"\x7fELF"
} Type guard
fn is_linux_elf(path: &Path) -> bool {
let mut magic = [0u8; 6];
let Ok(mut f) = std::fs::File::open(path) else { return false };
std::io::Read::read_exact(&mut f, &mut magic).is_ok()
&& &magic[..4] == b"\x7fELF"
&& matches!(magic[4], 1 | 2)
&& matches!(magic[5], 1 | 2)
} Try / catch
match elf_interpreter(&bytes) {
Err(e) if e.to_string().contains("not an ELF executable") => {
// mise_bin points at a script or wrong-platform binary: fix config, don't retry
eyre::bail!("mise_bin must be a Linux ELF executable; got {}", mise_bin.display());
}
other => other?,
} Prevention
- Check 'file <binary>' shows 'ELF ... for Linux' before setting mise_bin
- Never wrap mise in a shell script for upload; use mise_env for environment tweaks
- Verify checksums after copying binaries between machines
When it happens
Trigger: Setting mise_bin to a wrapper script or a wrong-platform binary (macOS mise) while the remote is Linux; a partially downloaded/corrupted local binary; a symlink target that is a script.
Common situations: Teams wrapping mise in a launcher script for env tweaks; copying binaries between platforms manually; disk/cache corruption or interrupted downloads.
Related errors
- unsupported ELF byte order
- unsupported ELF class
- remote host '{}' does not provide the dynamic loader require
- unsafe ELF interpreter path: {interpreter:?}
- trimPrefix requires exactly 2 arguments
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/b8c5b7be163b037c.
Report an issue: GitHub.