libnyanpasu/clash-nyanpasu · error
failed to parse config: {e}
Error message
failed to parse config: {e} What it means
detect_baseline reads the hotkey config.yaml to decide which migration baseline the installation is at. It parses the file into a serde_yaml Mapping; if parsing fails, this error is returned instead of a revision number, so the migration framework cannot determine the starting point.
Source
Thrown at backend/tauri/src/core/migration/modules/storage.rs:30
const HOTKEYS_KEY: &str = "hotkeys";
pub struct StorageMigrator;
impl ModuleMigrator for StorageMigrator {
fn module(&self) -> &'static str {
"storage"
}
fn detect_baseline(&self, ctx: &Ctx) -> anyhow::Result<u64> {
let config_path = ctx.nyanpasu_config_path();
if !config_path.exists() {
return Ok(current_revision());
}
let raw = std::fs::read_to_string(&config_path)?;
let config: Mapping = serde_yaml::from_str(&raw)
.map_err(|e| anyhow::anyhow!("failed to parse config: {e}"))?;
if config
.get(HOTKEYS_KEY)
.is_some_and(|value| value.as_sequence().is_some())
{
Ok(0)
} else {
Ok(current_revision())
}
}
fn steps(&self) -> &'static [&'static dyn MigrationStep] {
&STEPS
}
}
#[derive(Debug, Clone, Copy)]
pub struct MigrateHotkeysToKv;
View on GitHub (pinned to f7dbce2997)
Solutions
- Fix the YAML syntax error at the line/column reported in {e}.
- Restore config.yaml from backup or let the app regenerate defaults by moving the corrupt file aside.
- Validate externally with a YAML parser before re-running migration.
- Ensure the file is UTF-8 without BOM, spaces-only indentation.
Example fix
// before
let config: Mapping = serde_yaml::from_str(&raw)
.map_err(|e| anyhow::anyhow!("failed to parse config: {e}"))?;
// after
let config: Mapping = serde_yaml::from_str(&raw)
.with_context(|| format!("failed to parse config at {} for baseline detection", config_path.display()))?; Defensive patterns
Strategy: validation
Validate before calling
fn config_yaml_ok(path: &Path) -> Result<(), String> {
let raw = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
serde_yaml::from_str::<serde_yaml::Mapping>(&raw)
.map(|_| ())
.map_err(|e| format!("{}: {e}", path.display()))
} Type guard
fn is_valid_config_yaml(raw: &str) -> bool {
serde_yaml::from_str::<serde_yaml::Mapping>(raw).is_ok()
} Try / catch
let config: Mapping = match serde_yaml::from_str(&raw) {
Ok(c) => c,
Err(e) => {
eprintln!("cannot detect baseline, config.yaml invalid: {e}");
eprintln!("fix or restore config.yaml, then re-run migration");
return Err(anyhow::anyhow!("failed to parse config: {e}"));
}
}; Prevention
- Validate config.yaml with a linter after any manual edit
- Keep edits in the UI where possible; treat raw YAML edits as risky
- Save as UTF-8 (no BOM) with spaces-only indentation
- Maintain backups of config.yaml before upgrading versions
When it happens
Trigger: config.yaml exists but serde_yaml::from_str::<Mapping> fails: invalid YAML syntax, top-level non-mapping document, duplicate keys, BOM/non-UTF8 bytes, or truncation from a previous bad write.
Common situations: User hand-edited config.yaml and broke syntax; corrupt file from an old version or crash; encoding issues from external editors.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unrecognized typed config migration state: existing {} is ne
- failed to parse profiles: {e}
- failed to serialize config: {e}
- cannot repair typed clash config before split_legacy_config
- partial typed config migration state: existing [{}], missing
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/160d634305d5e599.
Report an issue: GitHub.