{"record":{"id":"13a61641799c8213","repo":"astrid-runtime/astrid","slug":"executable-replacement-set-must-not-be-empty","errorCode":null,"errorMessage":"executable replacement set must not be empty","messagePattern":"executable replacement set must not be empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/platform_fs.rs","lineNumber":826,"sourceCode":"\n    #[cfg(windows)]\n    {\n        windows::replace_executable_set(install_dir, extract_dir, names)\n    }\n\n    #[cfg(not(windows))]\n    {\n        replace_executable_set_by_rename(install_dir, extract_dir, names)\n    }\n}\n\nfn validate_replacement_inputs(\n    install_dir: &Path,\n    extract_dir: &Path,\n    names: &[&str],\n) -> io::Result<()> {\n    if names.is_empty() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"executable replacement set must not be empty\",\n        ));\n    }\n    if !install_dir.is_dir() || !extract_dir.is_dir() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"executable replacement directories must exist\",\n        ));\n    }\n\n    let mut unique = HashSet::with_capacity(names.len());\n    for name in names {\n        let mut components = Path::new(name).components();\n        if !matches!(components.next(), Some(Component::Normal(_)))\n            || components.next().is_some()\n            || !unique.insert(*name)\n        {","sourceCodeStart":808,"sourceCodeEnd":844,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs.rs#L808-L844","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Populate `names` with at least one executable name actually present in `extract_dir` before calling","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","Verify the extraction step ran and produced the expected executables; fix the extraction/manifest logic that yielded an empty list"],"exampleFix":"// before\nreplace_executable_set(&install_dir, &extract_dir, &executables)?;\n// after\nif executables.is_empty() {\n    return Err(anyhow!(\"no executables extracted from release archive\"));\n}\nreplace_executable_set(&install_dir, &extract_dir, &executables)?;","handlingStrategy":"validation","validationCode":"if names.is_empty() {\n    return Err(anyhow!(\"refusing to update: no executables listed\"));\n}","typeGuard":null,"tryCatchPattern":"match replace_executable_set(&install_dir, &extract_dir, &names) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && names.is_empty() => {\n        eprintln!(\"no executables extracted; skipping update\");\n    }\n    other => other.map_err(Into::into),\n}","preventionTips":["Assert the executable list is non-empty right after extraction","Treat an empty archive manifest as an extraction failure, not a valid update set","Log the archive contents when building the name list"],"tags":["validation","invalid-input","empty-list","self-update"],"backgroundTag":"empty-required-field","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}