{"record":{"id":"fd35a1bbd6f3eaa6","repo":"libnyanpasu/clash-nyanpasu","slug":"legacy-mutation-failed-error","errorCode":null,"errorMessage":"legacy mutation failed: {error:#}","messagePattern":"legacy mutation failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/bridge/verge.rs","lineNumber":267,"sourceCode":"        let prepared = self\n            .legacy_store\n            .prepare_commit(&managed.legacy_verge_path, state.clone())?;\n        self.replace_typed_config_from_legacy(state, move || prepared.commit())\n            .await?;\n        Ok(())\n    }\n\n    pub async fn run_legacy_verge_mutation<F, Fut>(&self, mutate: F) -> ClientResult<()>\n    where\n        F: FnOnce() -> Fut,\n        Fut: Future<Output = anyhow::Result<()>>,\n    {\n        let managed = self.managed()?;\n        let _guard = managed.verge_update_lock.lock().await;\n        let previous = self.legacy_store.snapshot()?;\n        if let Err(error) = mutate().await {\n            return Err(Self::legacy_mutation_partial(\n                anyhow::anyhow!(\"legacy mutation failed: {error:#}\"),\n                None,\n            ));\n        }\n        // TODO(actor-migration): compatibility bridge for legacy side-effect writers.\n        // Reason: feat::patch_verge still executes OS effects while producing legacy state.\n        // Remove when: side effects are prepared and committed by typed domain services.\n        let desired = self.legacy_store.snapshot()?;\n        let patch = legacy_patch_between(&previous, &desired)?;\n        // Captured before `patch` is moved into `desired.patch_config(patch)`\n        // below: the post-commit reconcile must build the runtime config from\n        // the just-committed typed state, never from the pre-commit draft\n        // (AGENTS.md section 10: commit first, then side effects).\n        let reconcile_tun = patch.enable_tun_mode.is_some();\n        let restore = self\n            .legacy_store\n            .prepare_restore(&managed.legacy_verge_path, previous)\n            .map_err(|error| Self::legacy_mutation_partial(error, None))?;\n        if let Err(error) = restore.commit() {","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/bridge/verge.rs#L249-L285","documentation":"Thrown by `run_legacy_verge_mutation` when the legacy mutation closure (e.g. `feat::patch_verge`) returns an error. Since nothing was committed yet, the error is wrapped as a 'partial mutation' result with no restore information (`None`), reporting `legacy mutation failed: {error:#}`. It marks the legacy side-effect compatibility bridge (TODO(actor-migration)) failing before any on-disk state changed.","triggerScenarios":"Calling `patch_verge_config` routed through `LegacyVergePatchRoute::LegacySideEffects` where the `mutate()` future (`crate::feat::patch_verge`) fails — e.g. invalid patch payload rejected by the legacy writer, OS side-effect failure, or core update error.","commonSituations":"User submits a verge config patch with values the legacy `feat::patch_verge` cannot apply; system proxy or TUN side effect fails mid-patch; underlying config store inaccessible.","solutions":["Read the wrapped `{error:#}` chain for the root cause from feat::patch_verge and fix the offending patch payload.","If the mutation route should no longer use legacy side effects, switch the patch route to the typed path (`apply_typed_config_patch_plan`) so this bridge is not exercised.","Validate the patch fields before calling patch_verge_config (e.g. tun mode, system proxy flags) to catch invalid values early.","No state was committed in this branch — simply correct inputs and retry; no manual restore is needed."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// validate the patch payload before invoking the legacy route\nfn validate_verge_patch(patch: &IVerge) -> Result<(), String> {\n    if let Some(tun) = patch.enable_tun_mode {\n        if !matches!(tun, true | false) { return Err(\"enable_tun_mode must be bool\".into()) }\n    }\n    Ok(())\n}","typeGuard":"fn is_legacy_mutation_failure(err: &ClientError) -> bool {\n    err.to_string().starts_with(\"legacy mutation failed:\")\n}","tryCatchPattern":"match bridge.patch_verge_config(payload).await {\n    Err(e) if e.to_string().starts_with(\"legacy mutation failed\") => {\n        // nothing committed; surface validation/root-cause to user and retry after fix\n        ui.report_validation_error(e);\n    }\n    other => other?,\n}","preventionTips":["Validate patch fields against the schema before calling patch_verge_config.","Migrate callers off LegacyVergePatchRoute::LegacySideEffects to the typed plan route.","Check OS side-effect prerequisites (system proxy privileges, TUN adapter) before patching.","Log the full `{error:#}` chain, not just the top message, to find the feat::patch_verge root cause."],"tags":["rust","tauri","legacy-compat","config-patch","migration-bridge"],"backgroundTag":"deprecated-api-usage","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}