astrid-runtime/astrid · error
executable replacement directories must exist
Error message
executable replacement directories must exist
What it means
`validate_replacement_inputs` requires both `install_dir` and `extract_dir` to be existing directories. If either `std::path::Path::is_dir()` returns false — path missing, is a file, or is unreachable — the call fails with `InvalidInput` before any staging or renaming occurs.
Solutions
- Verify both paths with `Path::is_dir()` before calling and create `extract_dir` via extraction or `create_dir_all` if missing
- Confirm the configured install directory actually exists and contains the executables being replaced
- Re-run the archive extraction step and confirm it succeeded before attempting replacement
Example fix
// before
replace_executable_set(&install_dir, &extract_dir, &names)?;
// after
if !install_dir.is_dir() {
std::fs::create_dir_all(&install_dir)?;
}
if !extract_dir.is_dir() {
return Err(anyhow!("extract dir missing: {}", extract_dir.display()));
}
replace_executable_set(&install_dir, &extract_dir, &names)?; Defensive patterns
Strategy: validation
Validate before calling
if !install_dir.is_dir() {
std::fs::create_dir_all(install_dir)?;
}
if !extract_dir.is_dir() {
return Err(anyhow!("extract dir missing: {}", extract_dir.display()));
} Type guard
fn both_dirs_exist(a: &Path, b: &Path) -> bool {
a.is_dir() && b.is_dir()
} Try / catch
match replace_executable_set(&install_dir, &extract_dir, names) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {
eprintln!("check install_dir/extract_dir exist as directories: {e}");
}
other => other.map_err(Into::into),
} Prevention
- Run extraction before replacement and verify it created the directory
- Resolve install/extract dirs from validated config, not raw env strings
- Re-check directory existence immediately before the update call
- Watch for temp-dir cleaners deleting extract_dir between steps
When it happens
Trigger: Calling `replace_executable_set` with an `extract_dir` that was never created (archive extraction skipped or failed), an `install_dir` typo, or either path pointing at a file instead of a directory; also when the path was deleted by another process between planning and the call.
Common situations: Extraction to a temp dir failed silently earlier and the temp dir was cleaned up; wrong env var/config key supplying the install directory; running the updater before the first install created the install dir; symlinks whose targets are gone.
Related errors
- Astrid volume is not a regular file
- cannot resolve install directory for
- capsule projection contains a special file
- capsule projection path is not UTF-8
- capsule source is neither a directory nor a regular file
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/a83ed7c089585403.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-core/src/platform_fs.rs:832
#[cfg(not(windows))]
{
replace_executable_set_by_rename(install_dir, extract_dir, names)
}
}
fn validate_replacement_inputs(
install_dir: &Path,
extract_dir: &Path,
names: &[&str],
) -> io::Result<()> {
if names.is_empty() {
return Err(io::Error::new(
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}'"),
));
}
View on GitHub (pinned to affd8760f4)