astrid-runtime/astrid · error
release archive is missing
Error message
release archive is missing '{name}': {error} What it means
Every listed executable must physically exist in `extract_dir`. When `std::fs::symlink_metadata(extract_dir.join(name))` fails, `validate_replacement_inputs` re-raises the OS error wrapped as `release archive is missing '<name>'`. The set is rejected before any live files are touched, so the current installation stays intact.
Solutions
- Verify the file exists at `extract_dir.join(name)` and re-run extraction if it is missing
- Check the name's exact case and platform suffix against the extracted archive contents (list the dir and match)
- Use the same manifest/archive pair for extraction and the `names` list to avoid cross-release mismatches
Example fix
// before
replace_executable_set(&install_dir, &extract_dir, &["astrid"])?;
// after
let names: Vec<&str> = if cfg!(windows) { &["astrid.exe"] } else { &["astrid"] };
replace_executable_set(&install_dir, &extract_dir, names)?; Defensive patterns
Strategy: validation
Validate before calling
let missing: Vec<_> = names.iter()
.filter(|n| !extract_dir.join(n).exists())
.collect();
if !missing.is_empty() {
return Err(anyhow!("missing from extract dir: {missing:?}"));
} Try / catch
match replace_executable_set(&install_dir, &extract_dir, names) {
Err(e) if e.to_string().starts_with("release archive is missing") => {
eprintln!("re-extract the archive; {e}");
}
other => other.map_err(Into::into),
} Prevention
- Verify the archive checksum and completeness after download/extraction
- Match name lists and archives from the same release manifest
- Check case-sensitivity and platform suffixes (.exe) when constructing names
- List extract_dir contents and diff against names before updating
When it happens
Trigger: Calling `replace_executable_set` with a name absent from `extract_dir` — archive extraction skipped that file, the name was misquoted or case-mismatches (`Astrid` vs `astrid` on a case-sensitive filesystem), or the extracted platform suffix (e.g. `.exe`) was stripped from the name.
Common situations: Extracting a truncated or partially downloaded archive; wrong architecture/platform archive extracted while the name list came from a manifest for another platform; names built from a previous release's manifest that no longer match.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- cannot resolve install directory for
- capsule path escaped source root
- capsule path is not valid UTF-8
- capsule source disappeared while preparing replacement
- {detail}: {error}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/0ed1e518789b604b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-core/src/platform_fs.rs:853
));
}
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}"),
));
}
}
Ok(())
}
#[cfg(not(windows))]
fn replace_executable_set_by_rename(
install_dir: &Path,
extract_dir: &Path,View on GitHub (pinned to affd8760f4)