unicity-aos/aos-ce · error · io::Error
legacy runtime etc contains a non-UTF-8 path
Error message
legacy runtime etc contains a non-UTF-8 path
What it means
copy_etc_state reads the legacy runtime's etc directory and converts each entry name to String so it can be checked against ETC_ALLOWLIST; a non-UTF-8 name inside etc produces this InvalidInput error. It prevents copying unknown, undecodable config paths into the new runtime layout.
Solutions
- Rename or remove the non-UTF-8 entry inside legacy etc/ so only allowlisted names remain
- Move unknown config files out of etc/ (back them up) before migrating
- List etc/ contents and verify each name decodes as UTF-8 and appears in the allowlist before running migration
Example fix
// before legacy/etc/ config.toml \x80backup/ // after legacy/etc/ config.toml
Defensive patterns
Strategy: validation
Validate before calling
fn etc_entries_clean(etc: &std::path::Path, allowlist: &[&str]) -> bool {
std::fs::read_dir(etc)
.map(|entries| entries.filter_map(|e| e.ok()).all(|e| {
e.file_name().to_str().map(|n| allowlist.contains(&n)).unwrap_or(false)
}))
.unwrap_or(false)
} Try / catch
match migrate_runtime(&source, ...) {
Ok(()) => {},
Err(e) if e.to_string().contains("etc contains a non-UTF-8 path") =>
eprintln!("remove or rename undecodable entries under legacy etc/ before migrating"),
Err(e) => return Err(e),
} Prevention
- Keep only allowlisted config files in legacy etc/; move extras elsewhere first
- Back up and remove files with undecodable names before migration
- Validate etc/ contents (UTF-8 + allowlist membership) as a pre-flight step
- Restrict write access to etc/ so foreign tools cannot drop arbitrary files there
When it happens
Trigger: Calling migrate_runtime when a file or subdirectory inside the legacy runtime's etc/ has a non-UTF-8 name, or a name not on ETC_ALLOWLIST (which then yields the adjacent invalid-name error).
Common situations: Old config dirs containing files created with legacy encodings; manually dropped-in config files with binary names; extraneous config files added after the original install.
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
- imported capsule installation contains a non-UTF-8 name
- 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/a05129253391fde7.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/migration.rs:792
}
Ok(())
}
fn copy_etc_state(source_root: &Path, staging: &Path, entries: &mut Vec<Entry>) -> io::Result<()> {
let source = source_root.join("etc");
let metadata = match fs::symlink_metadata(&source) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
Err(error) => return Err(error),
};
if metadata.file_type().is_symlink() || !metadata.is_dir() {
return invalid("legacy runtime etc must be a real directory");
}
for entry in fs::read_dir(&source)? {
let entry = entry?;
let name = entry.file_name().into_string().map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"legacy runtime etc contains a non-UTF-8 path",
)
})?;
if !ETC_ALLOWLIST.contains(&name.as_str()) {
return invalid(&format!(
"legacy runtime contains unsupported configuration `etc/{name}`; migration refuses to omit it"
));
}
let relative = PathBuf::from("etc").join(&name);
copy_tree(&entry.path(), &staging.join(&relative), &relative, entries)?;
}
Ok(())
}
fn copy_if_present(
source: &Path,
destination: &Path,View on GitHub (pinned to f6f22024fb)