libnyanpasu/clash-nyanpasu · error

failed to serialize profiles: {e}

Error message

failed to serialize profiles: {e}

What it means

write_profiles_atomic serializes the profiles Mapping to YAML and atomically writes it to disk; it is used by both the migration run and rollback paths. If serde_yaml::to_string fails on the Mapping, the write is aborted with this error and the on-disk profiles file is left untouched (atomic write never starts).

Source

Thrown at backend/tauri/src/core/migration/modules/profiles.rs:827

    if let Some(valid) = doc.get("valid")
        && !valid.is_null()
    {
        out.insert("valid".into(), valid.clone());
    }
    out.insert("items".into(), Value::Sequence(new_items));
    Ok(out)
}

/// Atomically persist a profiles mapping, mirroring [`crate::utils::help::save_yaml`]
/// but writing through a temp file + rename so a crash mid-write can never
/// truncate the user's `profiles.yaml`.
fn write_profiles_atomic(
    path: &std::path::Path,
    profiles: &Mapping,
    prefix: Option<&str>,
) -> anyhow::Result<()> {
    let body = serde_yaml::to_string(profiles)
        .map_err(|e| anyhow::anyhow!("failed to serialize profiles: {e}"))?;
    let content = match prefix {
        Some(prefix) => format!("{prefix}\n\n{body}"),
        None => body,
    };
    crate::core::migration::fs::atomic_write(path, content.as_bytes())
}

fn current_revision() -> u64 {
    STEPS.last().map(|step| step.revision()).unwrap_or_default()
}

fn migrate_profile_data(mut mapping: Mapping) -> Mapping {
    if let Some(items) = mapping.get_mut("items")
        && let Some(items) = items.as_sequence_mut()
    {
        for item in items {
            if let Some(item) = item.as_mapping_mut()
                && let Some(ty) = item.get("type").cloned()

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Trace which transform produced the Mapping and ensure it only inserts serde_yaml-supported values (string keys, scalars, sequences, mappings).
  2. Inspect {e} for the offending key/type and fix the transform to coerce it (e.g. stringify keys).
  3. Restore profiles.yaml.bak — the error means the original file was not modified.
  4. If it comes from parsed user data, round-trip the Mapping (to_string then from_str) early to catch unserializable content before mutation.

Example fix

// before
let body = serde_yaml::to_string(profiles)
    .map_err(|e| anyhow::anyhow!("failed to serialize profiles: {e}"))?;
// after
let body = serde_yaml::to_string(profiles)
    .with_context(|| format!("failed to serialize profiles for {} — Mapping contains unserializable values", path.display()))?;
Defensive patterns

Strategy: try-catch

Validate before calling

fn mapping_round_trips(m: &serde_yaml::Mapping) -> bool {
    serde_yaml::to_string(m)
        .ok()
        .and_then(|s| serde_yaml::from_str::<serde_yaml::Mapping>(&s).ok())
        .is_some()
}

Type guard

null

Try / catch

let body = match serde_yaml::to_string(profiles) {
    Ok(b) => b,
    Err(e) => {
        eprintln!("profiles Mapping unserializable, original file untouched: {e}");
        return Err(anyhow::anyhow!("failed to serialize profiles: {e}"));
    }
};

Prevention

When it happens

Trigger: serde_yaml::to_string(profiles) errors because the Mapping contains values serde_yaml cannot serialize — non-string keys outside serde_yaml's supported set, or values produced upstream that violate serde_yaml's model.

Common situations: A migration transform inserted an exotic value (e.g. tagged or non-string-keyed data) into the Mapping; version-skew between serde_yaml and produced types; practically rare since inputs originate from parsed YAML.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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