libnyanpasu/clash-nyanpasu · error

failed to parse config: {e}

Error message

failed to parse config: {e}

What it means

Thrown by the app_config migration module's `detect_baseline`, which reads the Nyanpasu config YAML and parses it into a `serde_yaml::Mapping` to decide whether migrations are needed. If the file's content is not valid YAML, `serde_yaml::from_str` fails and the error is wrapped as "failed to parse config: {e}" with serde_yaml's message appended. The file exists, but its content is unreadable as YAML.

Source

Thrown at backend/tauri/src/core/migration/modules/app_config.rs:40

const NETWORK_STATISTIC_WIDGET_KEY: &str = "network_statistic_widget";

pub struct AppConfigMigrator;

impl ModuleMigrator for AppConfigMigrator {
    fn module(&self) -> &'static str {
        "app_config"
    }

    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 needs_language_option_migration(&config)
            || needs_theme_setting_migration(&config)
            || needs_network_statistic_widget_migration(&config)
            || needs_language_case_migration(&config)
        {
            Ok(0)
        } else {
            Ok(current_revision())
        }
    }

    fn steps(&self) -> &'static [&'static dyn MigrationStep] {
        &STEPS
    }
}

#[derive(Debug, Clone, Copy)]
pub struct MigrateLanguageOption;

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Open the config file at the logged path and fix the YAML syntax error reported after the colon in the message
  2. Restore the config from backup or delete/rename the corrupt file so the app regenerates defaults (note: settings will reset)
  3. Validate the YAML with a linter (e.g. `yamltidy`/online parser) before saving hand edits
  4. Ensure writes go through crash-safe paths like `atomic_write` instead of direct truncating writes
Defensive patterns

Strategy: try-catch

Validate before calling

fn config_yaml_is_valid(path: &std::path::Path) -> bool {
    std::fs::read_to_string(path)
        .ok()
        .map(|raw| serde_yaml::from_str::<serde_yaml::Mapping>(&raw).is_ok())
        .unwrap_or(false)
}

Try / catch

match detect_baseline(&ctx) {
    Ok(rev) => rev,
    Err(e) if e.to_string().contains("failed to parse config") => {
        log::warn!("config unreadable, treating as unmigrated default: {e:#}");
        backup_and_reset_config(&ctx);
        current_revision()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: `detect_baseline` reads `ctx`'s nyanpasu config path, the file exists, but `serde_yaml::from_str::<Mapping>` fails — e.g. corrupt file, empty/garbage content, duplicate keys rejected by the parser, or the file was hand-edited with YAML syntax errors (bad indentation, tabs, unbalanced quotes).

Common situations: Crash or power loss mid-write leaving a truncated config; manual editing of the YAML config; a tool wrote JSON or another format into the YAML file; encoding issues from non-UTF-8 bytes on disk.

Understand the failure class

Related errors


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