libnyanpasu/clash-nyanpasu · error

path is not valid UTF-8: {}

Error message

path is not valid UTF-8: {}

What it means

The `to_utf8` helper in `core/actor_v2/local_host.rs` converts a `std::path::PathBuf` into a `Utf8PathBuf` and fails with this error when the path contains bytes that are not valid UTF-8 (possible on Unix where paths are arbitrary bytes). The actor-local host layer requires UTF-8 paths so they can be used in typed/string-based APIs, so non-UTF-8 paths are rejected eagerly with the lossy-decoded path in the message.

Source

Thrown at backend/tauri/src/core/actor_v2/local_host.rs:66

    let kind = match core {
        ClashCore::ClashPremium => CoreKind::ClashPremium,
        ClashCore::ClashRs | ClashCore::ClashRsAlpha => CoreKind::ClashRust,
        ClashCore::Mihomo | ClashCore::MihomoAlpha => CoreKind::Mihomo,
        ClashCore::Meow => CoreKind::Meow,
    };
    let binary_path = find_binary(&core_type)?;

    Ok(CoreSpec {
        kind,
        binary_path: to_utf8(binary_path)?,
        version: None,
        features: vec![],
    })
}

fn to_utf8(path: std::path::PathBuf) -> Result<Utf8PathBuf> {
    Utf8PathBuf::from_path_buf(path)
        .map_err(|path| anyhow::anyhow!("path is not valid UTF-8: {}", path.to_string_lossy()))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn the_local_host_spawns_under_a_temp_root() {
        let root = tempfile::TempDir::new().unwrap();
        let paths =
            PathResolver::with_base_dirs(root.path().join("config"), root.path().join("data"));

        let control = build(&paths).await.unwrap();

        let _ = control.status();
        assert!(!control.executor_is_closed());
    }

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Rename the offending file/directory so its path is valid UTF-8 (the error message shows the lossy name to find it).
  2. Set the system locale to a UTF-8 locale (e.g. LANG=en_US.UTF-8) so paths decode correctly.
  3. Check the configured app/profile data directory (env vars like HOME/XDG dirs) for non-UTF-8 bytes and fix it.
  4. If you control the caller, validate paths early with `to_str()` and surface a clear configuration error.

Example fix

// before
let host = LocalHost::build(to_utf8(path)?);
// after
let path = to_utf8(path).map_err(|e| {
    log::error!("app path must be UTF-8: {e}; move the app or fix the locale");
    e
})?;
let host = LocalHost::build(path);
Defensive patterns

Strategy: validation

Validate before calling

if path.to_str().is_none() {
    anyhow::bail!("path {:?} is not valid UTF-8; move the app or fix the system locale", path);
}

Type guard

fn is_utf8_path(path: &std::path::Path) -> bool {
    path.to_str().is_some()
}

Try / catch

let utf8_path = to_utf8(path)
    .with_context(|| format!("configure a UTF-8 app path (got {:?})", path))
    .map_err(|e| { log::error!("{e:#}"); e })?;

Prevention

When it happens

Trigger: Building or passing a filesystem path to the local-host actor helpers where a directory or filename was created with non-UTF-8 bytes (e.g. locale-mismatched bytes on Linux, files created by tools using non-UTF-8 encodings); any code path calling `to_utf8` with such a PathBuf.

Common situations: App installed under a path with non-UTF-8 bytes; user profiles/config dirs on a system with a legacy locale (LC_ALL=C, ISO-8859-1 filenames); extracted archives with mangled filenames; network mounts exposing raw-byte names.

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 libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/0c9d0843bf32538f. Report an issue: GitHub.