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

  1. 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.
  2. Check the path with `std::path::Path::to_str()` in your own setup before invoking the bootstrap and fail early with a clear message.
  3. 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.
  4. 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

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


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)