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

imported principal home contains a non-UTF-8 name

Error message

imported principal home contains a non-UTF-8 name

What it means

`archive_inactive_activation_state` iterates the imported `homes` directory and converts each principal entry name with `OsStr::into_string()`. If a principal home directory name is not valid UTF-8, the archive step cannot record it in the manifest, so an `InvalidInput` error is raised.

Solutions

  1. Find the offending entry with a byte-aware listing (e.g. `ls homes/ | LC_ALL=C grep -vP '^[\x00-\x7F\x80-\xFF]*$'` or `find homes -maxdepth 1 \! -regex '.*[[:print:]]*'`) and rename it to UTF-8.
  2. Re-create the affected principal's home with a UTF-8 name and move its contents across before migrating.
  3. Re-export the source state from a system using a UTF-8 locale so filenames are encoded as UTF-8.
  4. If the entry is garbage, delete it — inactive activation state that cannot be named cannot be preserved.

Example fix

// shell: rename non-UTF-8 principal home before migration
// before
mv $'homes/caf\xe9' homes/cafe

// after: homes/ contains only UTF-8 names, migration succeeds
Defensive patterns

Strategy: validation

Validate before calling

for entry in fs::read_dir(source.join("homes"))? {
    let entry = entry?;
    if entry.file_name().to_str().is_none() {
        return Err(anyhow!("non-UTF-8 principal home: {:?}", entry.file_name()));
    }
}

Type guard

fn is_utf8_name(e: &std::fs::DirEntry) -> bool { e.file_name().to_str().is_some() }

Try / catch

if err.to_string().contains("non-UTF-8 name") {
    eprintln!("rename the offending principal home to UTF-8 and retry");
}

Prevention

When it happens

Trigger: Running `migrate_runtime` on a source whose `homes/` directory contains an entry whose name has non-UTF-8 bytes (e.g. legacy-encoded usernames created by non-UTF-8 locale tooling).

Common situations: Systems where user accounts were created with Samba/legacy tools using Latin-1 names; imported archives (tar/zip) that decoded filenames incorrectly; manually created directories with raw-byte names.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

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

fn archive_inactive_activation_state(staging: &Path, entries: &mut [Entry]) -> io::Result<()> {
    let ce_capsules = unicity_ce_capsule_names()?;
    archive_non_default_profiles(staging, entries)?;

    let homes = staging.join("home");
    let homes_metadata = match fs::symlink_metadata(&homes) {
        Ok(metadata) => metadata,
        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
        Err(error) => return Err(error),
    };
    if homes_metadata.file_type().is_symlink() || !homes_metadata.is_dir() {
        return invalid("imported principal homes must be a real directory");
    }

    let mut principal_names = Vec::new();
    for principal in fs::read_dir(&homes)? {
        let principal = principal?;
        let principal_name = principal.file_name().into_string().map_err(|_| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                "imported principal home contains a non-UTF-8 name",
            )
        })?;
        let metadata = fs::symlink_metadata(principal.path())?;
        if metadata.file_type().is_symlink() {
            return invalid("imported principal home must be a real directory");
        }
        if metadata.is_file() {
            continue;
        }
        if !metadata.is_dir() {
            return invalid("imported principal home contains a special file");
        }
        principal_names.push(principal_name);
    }

    for principal_name in principal_names {

View on GitHub (pinned to f6f22024fb)