libnyanpasu/clash-nyanpasu · error

non-UTF-8 source

Error message

non-UTF-8 source

What it means

During core binary installation on Windows, when the plain tokio::fs::copy fails and an elevated (runas) cmd.exe copy is attempted, the source path must be converted to a &str. std::path::Path::to_str returns None when the OsStr is not valid UTF-8, and the adapter surfaces this as "non-UTF-8 source". The command passed to cmd.exe must be representable as a Rust string, hence the strict requirement.

Source

Thrown at backend/tauri/src/client/core_lifecycle/adapters.rs:31

pub struct FsBinaryInstaller;

#[async_trait]
impl BinaryInstaller for FsBinaryInstaller {
    async fn install(&self, artifact: &PreparedCoreBinary) -> anyhow::Result<()> {
        if let Err(error) = tokio::fs::copy(&artifact.source, &artifact.destination).await {
            tracing::warn!(%error, "core copy failed; requesting elevated installation");
            let source = artifact.source.clone();
            let destination = artifact.destination.clone();
            // The blocking task itself retains the staging files if its waiter dies.
            let staging = artifact.staging.clone();
            let status = tokio::task::spawn_blocking(move || {
                let _staging = staging;
                #[cfg(target_os = "windows")]
                {
                    let source = source
                        .to_str()
                        .ok_or_else(|| anyhow::anyhow!("non-UTF-8 source"))?;
                    let destination = destination
                        .to_str()
                        .ok_or_else(|| anyhow::anyhow!("non-UTF-8 destination"))?;
                    Ok::<_, anyhow::Error>(
                        runas::Command::new("cmd")
                            .args(&[
                                "/C",
                                "copy",
                                "/Y",
                                source,
                                destination.trim_start_matches(r"\\?\"),
                            ])
                            .status()?,
                    )
                }
                #[cfg(not(target_os = "windows"))]
                {
                    Ok::<_, anyhow::Error>(

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Move/download the core binary into an ASCII/UTF-8-safe path (e.g. a path under ProgramData or the app data dir) and retry installation.
  2. Rename the offending directory (e.g. the Windows user profile folder or temp dir) so its path is valid UTF-8.
  3. Use Path::to_string_lossy (accepting replacement chars) or cmd's short (8.3) path names via get_short_path_name to pass a representable path to cmd.exe.
  4. Replace the shell copy with a Rust-side elevated copy API that accepts OsString/PathBuf without UTF-8 conversion.

Example fix

// before
let source = source.to_str().ok_or_else(|| anyhow::anyhow!("non-UTF-8 source"))?;
// after
let source = source
    .to_str()
    .or_else(|| source.to_string_lossy().into_owned().is_utf8().then(|| source.to_string_lossy().into_owned()))
    .ok_or_else(|| anyhow::anyhow!("source path is not valid UTF-8: {:?}", source))?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_utf8_path(p: &std::path::Path) -> anyhow::Result<()> {
    anyhow::ensure!(p.to_str().is_some(), "path is not valid UTF-8: {:?}", p);
    Ok(())
}

Type guard

fn valid_utf8_path(p: &std::path::Path) -> Option<&str> { p.to_str() }

Try / catch

match installer.install(&artifact).await {
    Err(e) if e.to_string().contains("non-UTF-8") => {
        tracing::error!("path encoding issue; relocate staging dir to an ASCII path");
        install_via(&ascii_staging_dir, &artifact).await?;
    }
    Ok(()) => {},
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling FsBinaryInstaller::install with a PreparedCoreBinary whose artifact.source path contains bytes that are not valid UTF-8 (e.g. a staging dir under a user profile with non-UTF-8 characters) on Windows, after the initial non-elevated copy already failed.

Common situations: Windows usernames or temp directories containing characters outside the system's UTF-8-encodable set (CJK/legacy codepage names stored as WTF-16 without UTF-8 representation); sidecar cores downloaded into such paths.

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/c248050d7dc2f353. Report an issue: GitHub.