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

bundled product runtime path must have a parent

Error message

bundled product runtime path must have a parent

What it means

In checked_target_path, when the bundled product runtime target path does not exist (NotFound), the code canonicalizes the parent and rejoins the final component. If the path has no parent (e.g. a bare root-relative component like Path::new("runtime")), parent() returns None and this InvalidInput error is thrown. It guards the NotFound repair path from operating on degenerate paths.

Solutions

  1. Pass an absolute target path that includes a real parent directory (e.g. /opt/product/runtime)
  2. Check target.parent().is_some() and target.file_name().is_some() before invoking migrate_runtime
  3. If composing the path, join the final runtime directory onto an existing base directory

Example fix

// before
let target = Path::new("runtime");
migrate_runtime(target, ...)?;

// after
let target = Path::new("/opt/product/runtime");
migrate_runtime(target, ...)?;
Defensive patterns

Strategy: validation

Validate before calling

fn target_path_ok(target: &std::path::Path) -> bool {
    target.parent().is_some() && target.file_name().is_some()
}

Type guard

fn has_parent_and_name(p: &std::path::Path) -> Option<(std::path::PathBuf, std::ffi::OsString)> {
    Some((p.parent()?.to_path_buf(), p.file_name()?.to_os_string()))
}

Try / catch

match migrate_runtime(&target, ...) {
    Ok(()) => {},
    Err(e) if e.to_string().contains("must have a parent") =>
        eprintln!("use an absolute target path with a real parent directory"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling migrate_runtime with a bundled product runtime target path that has no parent directory component, such as a relative single-component path or a bare root path.

Common situations: Passing a target like "runtime" or "/" instead of a fully qualified installation path; constructing the target programmatically with a missing base directory.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

            let _ = fs::read(&pid)?;
        }
        Err(error) if error.kind() == io::ErrorKind::NotFound => {}
        Err(error) => return Err(error),
    }
    Ok(())
}

fn checked_target_path(path: &Path) -> io::Result<PathBuf> {
    match fs::symlink_metadata(path) {
        Ok(metadata) => {
            if metadata.file_type().is_symlink() || !metadata.is_dir() {
                return invalid("bundled product runtime must be a real directory");
            }
            path.canonicalize()
        }
        Err(error) if error.kind() == io::ErrorKind::NotFound => {
            let parent = path.parent().ok_or_else(|| {
                io::Error::new(
                    io::ErrorKind::InvalidInput,
                    "bundled product runtime path must have a parent",
                )
            })?;
            let name = path.file_name().ok_or_else(|| {
                io::Error::new(
                    io::ErrorKind::InvalidInput,
                    "bundled product runtime path must have a final component",
                )
            })?;
            Ok(parent.canonicalize()?.join(name))
        }
        Err(error) => Err(error),
    }
}

pub(crate) fn imported_legacy_distros(home: &AosHome) -> io::Result<Vec<LegacyDistro>> {
    let receipt = read_receipt(&home.migration_receipt())?;

View on GitHub (pinned to f6f22024fb)