{"record":{"id":"c248050d7dc2f353","repo":"libnyanpasu/clash-nyanpasu","slug":"non-utf-8-source","errorCode":null,"errorMessage":"non-UTF-8 source","messagePattern":"non-UTF-8 source","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/client/core_lifecycle/adapters.rs","lineNumber":31,"sourceCode":"\npub struct FsBinaryInstaller;\n\n#[async_trait]\nimpl BinaryInstaller for FsBinaryInstaller {\n    async fn install(&self, artifact: &PreparedCoreBinary) -> anyhow::Result<()> {\n        if let Err(error) = tokio::fs::copy(&artifact.source, &artifact.destination).await {\n            tracing::warn!(%error, \"core copy failed; requesting elevated installation\");\n            let source = artifact.source.clone();\n            let destination = artifact.destination.clone();\n            // The blocking task itself retains the staging files if its waiter dies.\n            let staging = artifact.staging.clone();\n            let status = tokio::task::spawn_blocking(move || {\n                let _staging = staging;\n                #[cfg(target_os = \"windows\")]\n                {\n                    let source = source\n                        .to_str()\n                        .ok_or_else(|| anyhow::anyhow!(\"non-UTF-8 source\"))?;\n                    let destination = destination\n                        .to_str()\n                        .ok_or_else(|| anyhow::anyhow!(\"non-UTF-8 destination\"))?;\n                    Ok::<_, anyhow::Error>(\n                        runas::Command::new(\"cmd\")\n                            .args(&[\n                                \"/C\",\n                                \"copy\",\n                                \"/Y\",\n                                source,\n                                destination.trim_start_matches(r\"\\\\?\\\"),\n                            ])\n                            .status()?,\n                    )\n                }\n                #[cfg(not(target_os = \"windows\"))]\n                {\n                    Ok::<_, anyhow::Error>(","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/client/core_lifecycle/adapters.rs#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet source = source.to_str().ok_or_else(|| anyhow::anyhow!(\"non-UTF-8 source\"))?;\n// after\nlet source = source\n    .to_str()\n    .or_else(|| source.to_string_lossy().into_owned().is_utf8().then(|| source.to_string_lossy().into_owned()))\n    .ok_or_else(|| anyhow::anyhow!(\"source path is not valid UTF-8: {:?}\", source))?;","handlingStrategy":"validation","validationCode":"fn ensure_utf8_path(p: &std::path::Path) -> anyhow::Result<()> {\n    anyhow::ensure!(p.to_str().is_some(), \"path is not valid UTF-8: {:?}\", p);\n    Ok(())\n}","typeGuard":"fn valid_utf8_path(p: &std::path::Path) -> Option<&str> { p.to_str() }","tryCatchPattern":"match installer.install(&artifact).await {\n    Err(e) if e.to_string().contains(\"non-UTF-8\") => {\n        tracing::error!(\"path encoding issue; relocate staging dir to an ASCII path\");\n        install_via(&ascii_staging_dir, &artifact).await?;\n    }\n    Ok(()) => {},\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["windows","path","encoding","filesystem"],"backgroundTag":"invalid-argument-format","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}