unicity-aos/aos-ce · error · io::Error
AOS capsule directory must be valid UTF-8 for the TOML…
Error message
AOS capsule directory must be valid UTF-8 for the TOML manifest
What it means
During manifest materialization, `materialize_manifest` joins the AOS capsule directory with an asset path and calls `Path::to_str()`. If the resulting absolute path cannot be represented as valid UTF-8, it cannot be embedded as a TOML string value, so an `io::Error` with kind `InvalidInput` is raised. The library throws this because TOML string values require valid UTF-8 and text-substituted manifests are explicitly avoided.
Solutions
- Rename the capsule directory (and its parents) so the full path is valid UTF-8, e.g. `mv` it to an ASCII/UTF-8 path.
- Check the path with `std::path::Path::to_str()` in your own setup before invoking the bootstrap and fail early with a clear message.
- If the path came from an environment variable or config, re-encode or normalize it (e.g. `String::from_utf8` on the source bytes) to UTF-8.
- On Linux, avoid building paths from raw `OsStrExt::as_bytes` unless they are known-valid UTF-8.
Example fix
// before
capsule_dir = PathBuf::from(OsString::from_vec(raw_bytes));
// after
let capsule_dir = PathBuf::from(String::from_utf8(raw_bytes)
.expect("capsule directory must be valid UTF-8")); Defensive patterns
Strategy: validation
Validate before calling
let capsule_dir: &Path = ...;
if capsule_dir.to_str().is_none() {
return Err(anyhow!("capsule directory path is not valid UTF-8: {:?}", capsule_dir));
} Type guard
fn is_utf8_path(p: &Path) -> bool { p.to_str().is_some() } Prevention
- Always create capsule directories from UTF-8 strings, never raw bytes.
- Validate paths with `Path::to_str()` during setup, before invoking the bootstrap.
- Normalize archive extractions with UTF-8 filename decoding (e.g. unzip with -O UTF-8).
When it happens
Trigger: Calling `ensure_unicity_ce_manifest` or a test path via `materialized_capsule_paths_are_toml_serialized_without_text_substitution` where the capsule directory path (or asset path under it) contains bytes that are not valid UTF-8 — e.g. paths built from raw bytes or containing Latin-1 encoded names.
Common situations: Mounting or extracting a capsule under a directory whose name was produced by a tool that does not enforce UTF-8 (e.g. zip archives with non-UTF-8 filename flags, NFS exports with legacy encodings), or constructing the capsule dir from `OsString`/byte data on Linux.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- AOS capsule directory contains a non-UTF-8 entry
- imported principal home contains a non-UTF-8 name
- imported capsule installation contains a non-UTF-8 name
- product release runtime bin contains a non-UTF-8 entry
- legacy runtime contains a non-UTF-8 top-level path
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/ecb9fabcdfe56440.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/lib.rs:799
"embedded distro has no capsules",
)
})?;
for capsule in capsules {
let source = capsule
.get("source")
.and_then(toml::Value::as_str)
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "embedded capsule has no source")
})?;
let asset = Path::new(source).file_name().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"embedded capsule source has no asset",
)
})?;
let absolute = capsule_dir.join(asset);
let absolute = absolute.to_str().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"AOS capsule directory must be valid UTF-8 for the TOML manifest",
)
})?;
capsule["source"] = toml::Value::String(absolute.to_owned());
}
toml::to_string_pretty(&manifest)
.map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))
}
#[cfg(test)]
mod tests {
use super::{
AosHome, RUNTIME_EXECUTABLE_NAMES, UNICITY_CE_MANIFEST, capsule_assets_from_manifest,
materialize_manifest, runtime_binary_name, runtime_daemon_binary_name,
};
use std::ffi::OsString;
use std::fs;View on GitHub (pinned to f6f22024fb)