astrid-runtime/astrid · error

executable replacement set must not be empty

Error message

executable replacement set must not be empty

What it means

`validate_replacement_inputs` rejects a call to `replace_executable_set` whose `names` slice is empty. Replacing a set of zero executables is considered a caller mistake — there is nothing to stage, install, or roll back, and an empty set likely signals a bug (e.g. a failed archive listing) rather than a legitimate no-op. It fails fast with `InvalidInput` before any filesystem mutation.

Solutions

  1. Populate `names` with at least one executable name actually present in `extract_dir` before calling
  2. If the source list can legitimately be empty, guard the call site and skip or surface an application-level error instead of calling the API
  3. Verify the extraction step ran and produced the expected executables; fix the extraction/manifest logic that yielded an empty list

Example fix

// before
replace_executable_set(&install_dir, &extract_dir, &executables)?;
// after
if executables.is_empty() {
    return Err(anyhow!("no executables extracted from release archive"));
}
replace_executable_set(&install_dir, &extract_dir, &executables)?;
Defensive patterns

Strategy: validation

Validate before calling

if names.is_empty() {
    return Err(anyhow!("refusing to update: no executables listed"));
}

Try / catch

match replace_executable_set(&install_dir, &extract_dir, &names) {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && names.is_empty() => {
        eprintln!("no executables extracted; skipping update");
    }
    other => other.map_err(Into::into),
}

Prevention

When it happens

Trigger: Calling `replace_executable_set(install_dir, extract_dir, &[])` — typically because the list of executables was built by filtering an archive manifest that matched nothing, or a hardcoded empty slice was passed.

Common situations: Extract step produced no matching binaries (wrong glob/prefix in archive); manifest parsing returned an empty list due to a format change; unit/integration tests accidentally pass an empty slice.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/13a61641799c8213. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-core/src/platform_fs.rs:826

    #[cfg(windows)]
    {
        windows::replace_executable_set(install_dir, extract_dir, names)
    }

    #[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)
        {

View on GitHub (pinned to affd8760f4)