unicity-aos/aos-ce · error · io::Error

bundled product runtime is not installed

Error message

bundled product runtime is not installed

What it means

validate_target checks that the bundled product runtime target exists via symlink_metadata and is a real directory (not a symlink). If the target path does not exist at all, the metadata lookup failure is mapped to this InvalidInput error. It means the migration destination runtime has never been installed.

Solutions

  1. Install the bundled product runtime at the target path first, then rerun migrate_runtime
  2. Verify the target path with fs::symlink_metadata(target).is_ok() before migrating
  3. Correct the configured install prefix if the runtime is installed at a different location
  4. Reinstall the product if the directory was deleted by a failed upgrade or cleanup

Example fix

// before
migrate_runtime(&target, ...)?; // target missing

// after
if target.symlink_metadata().is_err() {
    install_product_runtime(&target)?;
}
migrate_runtime(&target, ...)?;
Defensive patterns

Strategy: validation

Validate before calling

fn bundled_runtime_installed(target: &std::path::Path) -> bool {
    std::fs::symlink_metadata(target)
        .map(|m| m.is_dir())
        .unwrap_or(false)
}

Try / catch

match migrate_runtime(&target, ...) {
    Ok(()) => {},
    Err(e) if e.to_string().contains("bundled product runtime is not installed") =>
        eprintln!("install the product runtime at {} first", target.display()),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling migrate_runtime with validate flow where the target directory path does not exist on disk (symlink_metadata returns NotFound for the target).

Common situations: Running migration before the product installation step completed; a typo'd install prefix; the runtime directory was removed by cleanup or a failed upgrade.

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


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/1644f68d78c0931a. Report an issue: GitHub.

Appendix: source

Thrown at crates/unicity-aos-bootstrap/src/migration.rs:617

}

fn checked_root(path: &Path, description: &str) -> io::Result<PathBuf> {
    if !path.is_absolute() {
        return invalid(&format!("{description} must be an absolute path"));
    }
    let metadata = fs::symlink_metadata(path)?;
    if metadata.file_type().is_symlink() || !metadata.is_dir() {
        return invalid(&format!(
            "{description} must be a real directory, not a symlink"
        ));
    }
    path.canonicalize()
}

fn validate_target(target: &Path, release_runtime_bin: &Path) -> io::Result<()> {
    validate_release_runtime_bin(release_runtime_bin)?;
    let target_metadata = fs::symlink_metadata(target).map_err(|_| {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            "bundled product runtime is not installed",
        )
    })?;
    if target_metadata.file_type().is_symlink() || !target_metadata.is_dir() {
        return invalid("bundled product runtime must be a real directory");
    }
    let bin = target.join("bin");
    match fs::symlink_metadata(&bin) {
        Ok(bin_metadata) => {
            if bin_metadata.file_type().is_symlink() || !bin_metadata.is_dir() {
                return invalid("bundled product runtime bin must be a real directory");
            }
            if fs::read_dir(&bin)?.next().transpose()?.is_some() {
                return invalid(
                    "product runtime home contains data; migration refuses to merge state",
                );
            }

View on GitHub (pinned to f6f22024fb)