BoundaryML/baml · critical
failed to exec baml-cli: {err}
Error message
failed to exec baml-cli: {err} What it means
On Unix, the `baml` wrapper hands control to the resolved `baml-cli` binary via `Command::exec()`, which only returns on failure. If the exec syscall fails (permission denied, missing binary, bad interpreter, ENOEXEC), the wrapper throws this error wrapping the underlying io::Error.
Source
Thrown at baml_language/crates/baml/src/main.rs:454
// too would double it up.
let channel_warned = warn_if_channel_outdated(&selector, &version);
// A cache refresh (due at most once per TTL window) runs in the
// background while the command itself runs, instead of stalling it.
let refresh = start_lazy_refresh(&selector);
let mut command = Command::new(cli);
command.args(args);
command.env("BAML_WRAPPER_EXEC", "1");
command.env("BAML_WRAPPER_RESOLVED_TOOLCHAIN", &version);
let Some(refresh) = refresh else {
// Common case: nothing to refresh, so the wrapper can hand the
// process over entirely.
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
let err = command.exec();
return Err(anyhow!("failed to exec baml-cli: {err}"));
}
#[cfg(not(unix))]
{
let status = command.status().context("failed to run baml-cli")?;
return Ok(status.code().unwrap_or(1));
}
};
// Refresh in flight: run the command as a child (exec would kill the
// refresh thread), then give the refresh whatever remains of its budget
// and surface any warnings the fresh caches newly justify.
let status = command.status().context("failed to run baml-cli")?;
refresh.wait();
if !channel_warned {
warn_if_channel_outdated(&selector, &version);
}
Ok(status.code().unwrap_or(1))
}View on GitHub (pinned to bd85ce9dee)
Solutions
- Run `baml self-update` (or reinstall baml) to restore a healthy baml-cli binary.
- Check the exec bit on the resolved binary: `chmod +x $(which baml-cli)` or the toolchain path shown in the error.
- Verify the binary's filesystem is not mounted noexec: `mount | grep <path>`; remount with exec or relocate the toolchain.
- Inspect the wrapped io::Error text in the message (e.g. ENOENT vs EACCES) to target the specific cause.
Example fix
# before (exec fails: missing exec bit) $ baml generate error: failed to exec baml-cli: Permission denied (os error 13) # after $ chmod +x ~/.baml/toolchains/0.210.0/bin/baml-cli $ baml generate
Defensive patterns
Strategy: try-catch
Validate before calling
import os, shutil, stat
def can_exec_cli():
path = shutil.which("baml-cli")
if path is None:
raise SystemExit("baml-cli not found — run `baml self-update` or reinstall")
if not (os.stat(path).st_mode & stat.S_IXUSR):
raise SystemExit(f"baml-cli not executable: {path} — chmod +x") Type guard
function isExecutableFile(p: string): boolean {
try { fs.accessSync(p, fs.constants.X_OK); return fs.statSync(p).isFile(); }
catch { return false; }
} Try / catch
result = subprocess.run(["baml"] + args, capture_output=True)
if result.returncode != 0 and "failed to exec baml-cli" in result.stderr.decode():
# wrapper-level exec failure: reinstall before retrying
subprocess.run(["baml", "self-update"], check=True) Prevention
- Don't interrupt `baml self-update`; a partial install breaks exec later.
- Keep the baml install on an exec-mounted filesystem (avoid noexec /tmp or NAS).
- After copying or restoring backups, re-apply the executable bit.
- Read the wrapped io::Error (ENOENT/EACCES/ENOEXEC) to diagnose quickly.
When it happens
Trigger: Calling any pass-through `baml <args>` command where the resolved baml-cli binary cannot be exec'd: file not present despite stale state, non-executable permissions, corrupted install, or a filesystem mounted noexec.
Common situations: Interrupted self-update leaving a partial baml-cli, toolchain directory moved/deleted after `use`, copying the install onto a noexec mount (e.g. some /tmp mounts or network shares), or antivirus/quarantine stripping the exec bit.
Related errors
- failed to exec {}: {err}{origin}
- toolchain binary is not executable: {}{origin}
- baml.sys.exit({code})
- baml.panics.Exit
- ErrLoadLibrary
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/9a48c8564a6cb530.
Report an issue: GitHub.