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
- Verify the path printed in the message exists and is spelled correctly.
- Call fs::create_dir_all on the parent and create a default file if it should always exist.
- For optional files, check path.exists() before calling read_yaml and use a default value instead.
- 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
- Check path.exists() before read_yaml for optional files
- Create parent directories and seed default config on first launch
- Validate data-dir configuration after upgrades or directory moves
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
- unrecognized typed config migration state: existing {} is ne
- failed to parse config: {e}
- failed to parse config: {e}
- failed to serialize config: {e}
- failed to transform to yaml mapping "{}"
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/5f73c275e5aa91dc.
Report an issue: GitHub.