{"record":{"id":"a83ed7c089585403","repo":"astrid-runtime/astrid","slug":"executable-replacement-directories-must-exist","errorCode":null,"errorMessage":"executable replacement directories must exist","messagePattern":"executable replacement directories must exist","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/platform_fs.rs","lineNumber":832,"sourceCode":"    #[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        {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                format!(\"invalid or duplicate executable name '{name}'\"),\n            ));\n        }\n","sourceCodeStart":814,"sourceCodeEnd":850,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs.rs#L814-L850","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nreplace_executable_set(&install_dir, &extract_dir, &names)?;\n// after\nif !install_dir.is_dir() {\n    std::fs::create_dir_all(&install_dir)?;\n}\nif !extract_dir.is_dir() {\n    return Err(anyhow!(\"extract dir missing: {}\", extract_dir.display()));\n}\nreplace_executable_set(&install_dir, &extract_dir, &names)?;","handlingStrategy":"validation","validationCode":"if !install_dir.is_dir() {\n    std::fs::create_dir_all(install_dir)?;\n}\nif !extract_dir.is_dir() {\n    return Err(anyhow!(\"extract dir missing: {}\", extract_dir.display()));\n}","typeGuard":"fn both_dirs_exist(a: &Path, b: &Path) -> bool {\n    a.is_dir() && b.is_dir()\n}","tryCatchPattern":"match replace_executable_set(&install_dir, &extract_dir, names) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {\n        eprintln!(\"check install_dir/extract_dir exist as directories: {e}\");\n    }\n    other => other.map_err(Into::into),\n}","preventionTips":["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"],"tags":["filesystem","validation","missing-directory","self-update"],"backgroundTag":"directory-not-found","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"}