astrid-runtime/astrid · error
invalid or duplicate executable name
Error message
invalid or duplicate executable name '{name}' What it means
Each name in `names` must be exactly one `Normal` path component — no leading `/`, no `..`, no nested paths like `bin/app` — and must appear only once in the set. `validate_replacement_inputs` rejects anything else (or a duplicate) with `InvalidInput`. This guards against path traversal and ambiguous double-installation of the same executable.
Solutions
- Pass bare file names only (e.g. `"astrid"`), and normalize any archive-relative paths with `Path::file_name()` before building the list
- Deduplicate the list (e.g. via `HashSet` or `dedup()` after sorting) before calling
- Reject or skip entries containing separators, `..`, or that are empty, at list-construction time
Example fix
// before
let names: Vec<&str> = entries.iter().map(|e| e.path.as_str()).collect(); // "bin/astrid"
// after
let names: Vec<&str> = entries.iter()
.filter_map(|e| Path::new(e.path).file_name()?.to_str())
.collect::<HashSet<_>>().into_iter().collect(); Defensive patterns
Strategy: validation
Validate before calling
fn sanitize_name(name: &str) -> Option<&str> {
let p = std::path::Path::new(name);
if p.components().count() == 1 && matches!(p.components().next(), Some(std::path::Component::Normal(_))) {
Some(name)
} else {
None
}
}
let names: Vec<&str> = raw.into_iter().filter_map(sanitize_name).collect::<std::collections::HashSet<_>>().into_iter().collect(); Type guard
fn is_plain_file_name(name: &str) -> bool {
!name.is_empty() && std::path::Path::new(name).file_name() == Some(std::ffi::OsStr::new(name))
} Try / catch
match replace_executable_set(&install_dir, &extract_dir, &names) {
Err(e) if e.to_string().contains("invalid or duplicate executable name") => {
eprintln!("malformed executable list: {e}");
}
other => other.map_err(Into::into),
} Prevention
- Strip archive paths to file_name() before building the names list
- Deduplicate with a HashSet before calling
- Reject entries containing '/', '\\', or ".." at input time
- Validate manifests at load, not at install time
When it happens
Trigger: Passing `"bin/astrid"`, `"../astrid"`, `"/usr/bin/astrid"`, `"./astrid"`, `""`, or the same name twice in the `names` slice to `replace_executable_set`.
Common situations: Deriving names from archive paths that include subdirectories instead of stripping to the file name; a config listing the same executable twice; user-edited manifests containing absolute or relative paths; string joins producing empty entries.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- executable replacement set must not be empty
- durable capsule has unsafe WIT metadata path
- executable replacement directories must exist
- Invalid session ID (must be a UUID)
- private directory contains traversal
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/35299ac2e4b25b51.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-core/src/platform_fs.rs:845
io::ErrorKind::InvalidInput,
"executable replacement set must not be empty",
));
}
if !install_dir.is_dir() || !extract_dir.is_dir() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"executable replacement directories must exist",
));
}
let mut unique = HashSet::with_capacity(names.len());
for name in names {
let mut components = Path::new(name).components();
if !matches!(components.next(), Some(Component::Normal(_)))
|| components.next().is_some()
|| !unique.insert(*name)
{
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("invalid or duplicate executable name '{name}'"),
));
}
let source = extract_dir.join(name);
let metadata = std::fs::symlink_metadata(&source).map_err(|error| {
io::Error::new(
error.kind(),
format!("release archive is missing '{name}': {error}"),
)
})?;
if metadata.file_type().is_symlink() || !metadata.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("release executable is redirected or not regular: {name}"),
));
}View on GitHub (pinned to affd8760f4)