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
- 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.
- Re-create the affected principal's home with a UTF-8 name and move its contents across before migrating.
- Re-export the source state from a system using a UTF-8 locale so filenames are encoded as UTF-8.
- 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
- Create user/principal homes under a UTF-8 locale only.
- Extract archives with UTF-8 filename decoding.
- Pre-scan the homes directory for non-UTF-8 names before migrating.
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
- imported capsule installation contains a non-UTF-8 name
- legacy runtime etc contains a non-UTF-8 path
- AOS capsule directory contains a non-UTF-8 entry
- AOS capsule directory must be valid UTF-8 for the TOML…
- standalone runtime has no existing system lock; refusing an…
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)