libnyanpasu/clash-nyanpasu · error

config path is not UTF-8: {}

Error message

config path is not UTF-8: {}

What it means

This error is thrown by `utf8_path` when converting a `PathBuf` into `Utf8PathBuf` fails, i.e. the config file path contains bytes that are not valid UTF-8. On Windows, paths are UTF-16 and may contain unpaired surrogates; on Unix they may be arbitrary bytes. The client requires UTF-8 paths because config paths are passed through typed `Utf8PathBuf` values (serde/IPC-friendly).

Source

Thrown at backend/tauri/src/client/mod.rs:1340

    pub async fn rebuild_running_config(&self) -> Result<()> {
        self.reconcile_core()
            .await
            .map_err(client_error_from_core)?;
        self.inner.ui_sink.refresh_clash();
        Ok(())
    }

    pub(crate) async fn regenerate_runtime(&self) -> Result<()> {
        self.reconcile_core()
            .await
            .map(|_| ())
            .map_err(client_error_from_core)
    }
}

fn utf8_path(path: PathBuf) -> anyhow::Result<Utf8PathBuf> {
    Utf8PathBuf::from_path_buf(path)
        .map_err(|path| anyhow::anyhow!("config path is not UTF-8: {}", path.display()))
}

#[cfg(test)]
pub(crate) mod tests {
    use super::*;
    use crate::state::{
        mirror::{
            ClashLegacyBridge, NoopPreparedLegacyMirror, PreparedLegacyMirror, VergeLegacyBridge,
            WindowLegacyBridge,
        },
        profiles::ports::{
            CleanupOutcome, MaterializationReconcileReport, MockProfileFsPort,
            MockProfileMaterializationPort, MockRebuildNotifier, MockSubscriptionFetcher,
            PreparedCleanup, PreparedMaterialization, ProfileMaterializationPort,
        },
    };
    use camino::Utf8PathBuf;
    use nyanpasu_config::{

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Rename the config directory/file (or the user profile path) so it contains only valid UTF-8 characters
  2. Check the path with `Path::to_str()` before calling the API to detect the offending bytes
  3. Re-encode/recover the path via `String::from_utf8` on the raw bytes to find which component is invalid
  4. If on Windows, ensure the path is retrieved via UTF-8-safe APIs (`to_string_lossy` only masks the problem)

Example fix

// before
let path = std::env::var("CONFIG_PATH").unwrap(); // may carry non-UTF-8 bytes on some platforms
client.load_config(PathBuf::from(path)).await?;
// after
let path = std::env::var_os("CONFIG_PATH").unwrap();
if path.to_str().is_none() {
    eprintln!("CONFIG_PATH is not valid UTF-8: {:?}", path);
    return;
}
client.load_config(PathBuf::from(path)).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_utf8(path: &std::path::Path) -> Result<(), String> {
    match path.to_str() {
        Some(_) => Ok(()),
        None => Err(format!("path is not valid UTF-8: {:?}", path.as_os_str())),
    }
}

Type guard

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

Prevention

When it happens

Trigger: Calling any client config API (e.g. loading/patching a config file at backend/tauri/src/client/mod.rs:1340) where the resolved config path was constructed from an environment with non-UTF-8 characters — e.g. a user profile directory, home dir, or `--config` argument containing legacy-encoded bytes.

Common situations: Windows usernames or home directories with characters outside the system's UTF-8 conversion (CJK/emoji/legacy codepage names); Linux systems with filenames in non-UTF-8 locale encodings; paths built from raw OS strings read from the environment.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/7f0aa462fe6a21fa. Report an issue: GitHub.