libnyanpasu/clash-nyanpasu · error

file not found "{}"

Error message

file not found "{}"

What it means

read_yaml was given a path that does not exist on disk. The function guards with path.exists() and bails before attempting to read, because callers expect a file to be present (e.g. a merge mapping or config YAML).

Source

Thrown at backend/tauri/src/utils/help.rs:30

use serde_yaml::{Mapping, Value};
use std::{
    io::{BufWriter, Cursor},
    path::{Path, PathBuf},
    str::FromStr,
};
use tauri::{AppHandle, Manager, process::current_binary};
use tauri_plugin_shell::ShellExt;
use tracing::{debug, warn};
use tracing_attributes::instrument;

use crate::trace_err;
use tauri_plugin_opener::OpenerExt;

/// read data from yaml as struct T
pub fn read_yaml<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T> {
    let path = path.as_ref();
    if !path.exists() {
        bail!("file not found \"{}\"", path.display());
    }

    let yaml_str = fs::read_to_string(path)
        .with_context(|| format!("failed to read the file \"{}\"", path.display()))?;

    serde_yaml::from_str::<T>(&yaml_str).with_context(|| {
        format!(
            "failed to read the file with yaml format \"{}\"",
            path.display()
        )
    })
}

/// read mapping from yaml fix #165
pub fn read_merge_mapping(path: &PathBuf) -> Result<Mapping> {
    let mut val: Value = read_yaml(path)?;
    val.apply_merge()
        .with_context(|| format!("failed to apply merge \"{}\"", path.display()))?;

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Verify the path printed in the message exists and is spelled correctly.
  2. Call fs::create_dir_all on the parent and create a default file if it should always exist.
  3. For optional files, check path.exists() before calling read_yaml and use a default value instead.
  4. Confirm the app's data directory configuration points at the intended location.

Example fix

// before
let mapping: MergeMapping = help::read_yaml(&path)?;
// after
let mapping = if path.exists() {
    help::read_yaml(&path)?
} else {
    MergeMapping::default()
};
Defensive patterns

Strategy: validation

Validate before calling

let path = Path::new(&config_path);
if !path.exists() {
    // create defaults before reading
    if let Some(parent) = path.parent() { std::fs::create_dir_all(parent)?; }
    std::fs::write(path, default_yaml)?;
}

Type guard

fn file_exists(p: &std::path::Path) -> bool { p.is_file() }

Try / catch

match read_yaml::<MergeMapping, _>(&path) {
    Ok(v) => v,
    Err(e) if e.to_string().starts_with("file not found") => MergeMapping::default(),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling read_yaml::<T,_>(path) (directly or via read_merge_mapping) with a path to a file that was never created, was deleted, or whose path is wrong/typo'd.

Common situations: First launch before any user config has been written, switching data directories, or referencing an optional file (like a merge profile) without checking existence first.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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