unicity-aos/aos-ce · error · io::Error
imported capsule installation contains a non-UTF-8 name
Error message
imported capsule installation contains a non-UTF-8 name
What it means
Inside `archive_inactive_activation_state`, the inactive-capsules scan converts each capsule directory entry name with `into_string()`. If a capsule installation name under the imported state is not valid UTF-8, it cannot be represented in the migration manifest, so an `InvalidInput` error is raised.
Solutions
- List the inactive capsule directory byte-wise (`LC_ALL=C ls`) to identify the non-UTF-8 entry and rename it with a valid UTF-8 name.
- Reinstall or re-extract the affected capsule so its directory name is UTF-8, then retry the migration.
- Remove the offending capsule entry if it is no longer needed (it is inactive state and cannot be archived otherwise).
- Normalize the source state on a UTF-8 locale system (e.g. `convmv --notest -f latin1 -t utf8 -r <capsules-dir>`) before migrating.
Example fix
// shell: fix non-UTF-8 capsule directory name before migration // before convmv -f latin1 -t utf8 -r --notest run/capsules/ // after: all capsule names are valid UTF-8, migration proceeds
Defensive patterns
Strategy: validation
Validate before calling
for entry in fs::read_dir(capsules_dir)? {
let entry = entry?;
if entry.file_name().to_str().is_none() {
return Err(anyhow!("non-UTF-8 capsule name: {:?}", 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 or remove the offending capsule directory and retry");
} Prevention
- Install capsules only via tools that produce UTF-8 directory names.
- Normalize legacy-encoded capsule dirs with convmv before migrating.
- Pre-scan inactive capsule directories for non-UTF-8 names.
When it happens
Trigger: Running `migrate_runtime` where the imported inactive capsule installation directory contains an entry whose filename has non-UTF-8 bytes (e.g. capsule dirs created by scripts using legacy encodings).
Common situations: Capsule directories extracted from zip archives with non-UTF-8 filename flags; directories produced on a system with a non-UTF-8 locale; manual file operations using 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 principal home 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/f7756f7f89defbb8.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/migration.rs:390
let capsules_metadata = match fs::symlink_metadata(&capsules) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => continue,
Err(error) => return Err(error),
};
if capsules_metadata.file_type().is_symlink() || !capsules_metadata.is_dir() {
return invalid("imported capsule installation root must be a real directory");
}
if principal_name != "default" {
archive_path(staging, &relative, entries)?;
continue;
}
let mut inactive_capsules = Vec::new();
for capsule in fs::read_dir(&capsules)? {
let capsule = capsule?;
let name = capsule.file_name().into_string().map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"imported capsule installation contains a non-UTF-8 name",
)
})?;
let metadata = fs::symlink_metadata(capsule.path())?;
if metadata.file_type().is_symlink() {
return invalid("imported capsule installation must not be a symlink");
}
if !metadata.is_dir() && !metadata.is_file() {
return invalid("imported capsule installation contains a special file");
}
let active_ce_capsule = metadata.is_dir()
&& imported_capsule_package_name(&capsule.path()).as_deref() == Some(&name)
&& ce_capsules.contains(&name);
if !active_ce_capsule {
inactive_capsules.push(name);
}
}View on GitHub (pinned to f6f22024fb)