unicity-aos/aos-ce · error · std::io::Error
bundled executable must have a parent directory
Error message
bundled executable must have a parent directory
What it means
runtime_executable_command calls Path::parent() on the bundled executable path and, since parent() returns None only for paths with no parent component (e.g. a bare relative name resolved oddly or a root-less path), maps that to InvalidInput "bundled executable must have a parent directory". The parent is required to build the child process PATH that puts bundled sibling tools first.
Solutions
- Pass the full absolute path to the executable file (e.g. /opt/runtime/bin/unicityd), never a directory root or empty path.
- Resolve the executable with canonicalize() before invoking so the path always has a parent.
- Validate the override path points to an existing file before building the Command.
Example fix
// before
let exe = Path::new("");
let cmd = runtime.runtime_executable_command(exe, args)?;
// after
let exe = PathBuf::from("/opt/unicity/bin/unicityd");
debug_assert!(exe.is_file());
let cmd = runtime.runtime_executable_command(&exe, args)?; Defensive patterns
Strategy: validation
Validate before calling
fn require_parented_file(exe: &Path) -> Result<(), String> {
if exe.parent().is_none() {
return Err(format!("executable path {:?} has no parent; use a full file path", exe));
}
if !exe.is_file() {
return Err(format!("{:?} is not an existing file", exe));
}
Ok(())
} Type guard
fn is_full_executable_path(exe: &Path) -> bool {
exe.parent().is_some() && exe.is_file()
} Try / catch
match runtime.runtime_command_with_args(&exe, args) {
Err(e) if e.to_string().contains("must have a parent directory") => {
eprintln!("override executable must be a full file path, got {:?}", exe);
}
other => other?,
} Prevention
- Always pass absolute file paths (…/bin/<binary>) for executable overrides, never roots or bare names.
- Canonicalize configured executable paths at load time with std::fs::canonicalize.
- Add a startup assertion that every configured executable path has a parent and is a file.
When it happens
Trigger: Calling runtime_executable_command (via runtime_command_with_args or foreground_daemon_command) with an executable Path whose parent() is None — practically only paths like "/" or pathological inputs that yield no parent component.
Common situations: A misconfigured override pointing the executable at a filesystem root or empty/degenerate path; constructing the path programmatically and accidentally passing "" or "/" instead of the binary file path.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- must be an absolute path
- cannot construct the bundled runtime PATH
- cannot contain a platform PATH separator
- canonical document exceeds bound
- must not be empty
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/3b96306808fe7dfd.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/lib.rs:359
/// # Errors
/// Returns an error when the release runtime bin or inherited host PATH
/// cannot be represented safely as a child PATH.
pub fn runtime_command_with_args<I, S>(&self, args: I) -> io::Result<Command>
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let runtime_binary = self.runtime_binary();
self.runtime_executable_command(&runtime_binary, args)
}
fn runtime_executable_command<I, S>(&self, executable: &Path, args: I) -> io::Result<Command>
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let executable_parent = executable.parent().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"bundled executable must have a parent directory",
)
})?;
// An explicit absolute package override points at a complete runtime
// bundle, so keep its sibling tools ahead of the host PATH as well.
let path_prefix = match std::env::var_os("UNICITY_AOS_RUNTIME_BIN").map(PathBuf::from) {
Some(path) if path.is_absolute() => path
.parent()
.map(Path::to_path_buf)
.unwrap_or_else(|| executable_parent.to_path_buf()),
_ => self.release_runtime_bin_dir(),
};
let mut command = Command::new(executable);
command
.env("ASTRID_HOME", self.runtime_home())
.env("ASTRID_WORKSPACE_STATE_DIR", AOS_WORKSPACE_STATE_DIR)
.env("ASTRID_ENFORCED_DISTRO", self.unicity_ce_manifest_path())View on GitHub (pinned to f6f22024fb)