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
- 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.
- Rename the offending directory (e.g. the Windows user profile folder or temp dir) so its path is valid UTF-8.
- 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.
- 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
- Keep core staging/install directories under ASCII-safe paths (ProgramData / app data)
- Avoid deriving install paths from user names or free-form input on Windows
- Prefer PathBuf/OsString APIs end-to-end instead of converting paths to &str for shell commands
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
- non-UTF-8 destination
- path is not valid UTF-8: {}
- failed to get app_path
- managed profile path uses reserved private storage
- managed target is an unsupported reparse point: {}
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/c248050d7dc2f353.
Report an issue: GitHub.