{"record":{"id":"48e51bbb22ce8ce4","repo":"libnyanpasu/clash-nyanpasu","slug":"partial-typed-config-migration-state-existing","errorCode":null,"errorMessage":"partial typed config migration state: existing [{}], missing [{}]; restore or remove the typed config files before retrying","messagePattern":"partial typed config migration state: existing \\[(.+?)\\], missing \\[(.+?)\\]; restore or remove the typed config files before retrying","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/core/migration/modules/typed_config.rs","lineNumber":299,"sourceCode":"\nfn push_file_state(\n    existing: &mut Vec<&'static str>,\n    missing: &mut Vec<&'static str>,\n    exists: bool,\n    name: &'static str,\n) {\n    if exists {\n        existing.push(name);\n    } else {\n        missing.push(name);\n    }\n}\n\nfn partial_typed_file_state(\n    existing: Vec<&'static str>,\n    missing: Vec<&'static str>,\n) -> anyhow::Result<TypedFileState> {\n    bail!(\n        \"partial typed config migration state: existing [{}], missing [{}]; \\\n         restore or remove the typed config files before retrying\",\n        existing.join(\", \"),\n        missing.join(\", \")\n    );\n}\n\nfn validate_existing_typed_files(ctx: &Ctx) -> anyhow::Result<()> {\n    validate_existing_application_and_session(ctx)?;\n    read_yaml::<nyanpasu_config::clash::config::ClashConfig>(&ctx.clash_config_path())\n        .context(\"failed to validate existing clash config\")?;\n    Ok(())\n}\n\nfn validate_existing_application_and_session(ctx: &Ctx) -> anyhow::Result<()> {\n    read_yaml::<nyanpasu_config::application::NyanpasuAppConfig>(&ctx.application_config_path())\n        .context(\"failed to validate existing application config\")?;\n    read_yaml::<nyanpasu_config::state::PersistentState>(&ctx.session_state_path())","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/core/migration/modules/typed_config.rs#L281-L317","documentation":"This error is thrown by `partial_typed_file_state` during typed config migration when the on-disk state is inconsistent: some typed config files already exist while others expected for the migration are missing. The migration refuses to run in this half-applied state to avoid overwriting or duplicating partially migrated data. The operator must either restore the missing files or remove the existing ones so the migration can start from a clean, consistent state.","triggerScenarios":"Calling `typed_file_state` (which calls `partial_typed_file_state`) when the set of existing typed config files is neither empty nor complete — e.g. only some of the typed config files (existing list) are present on disk while others (missing list) are absent.","commonSituations":"A previous migration run was interrupted (crash, power loss, kill) after writing some typed config files; a user manually deleted one of several typed config files; a version downgrade removed some files while others remained; syncing/restore tools partially restored the config directory.","solutions":["Inspect the two lists in the error message: back up and remove the files listed under 'existing' to retry the migration from scratch.","Alternatively, restore/recreate the files listed under 'missing' (e.g. from backup or a previous installation) to complete the set so migration sees a consistent state.","After fixing, re-run the migration; if it keeps failing, wipe the typed config files entirely and let the migration regenerate them."],"exampleFix":"// before: partial state on disk\n~/.config/nyanpasu/typed/app.yaml        (exists)\n~/.config/nyanpasu/typed/verge.yaml      (missing)\n\n// after option 1: remove leftovers to start clean\nrm ~/.config/nyanpasu/typed/app.yaml\n\n// after option 2: restore the missing file from backup\ncp ~/backup/nyanpasu/typed/verge.yaml ~/.config/nyanpasu/typed/verge.yaml","handlingStrategy":"validation","validationCode":"// Check typed config dir consistency before triggering migration\nfn typed_state_is_consistent(expected: &[&str], dir: &Path) -> bool {\n    let present: Vec<_> = expected.iter().filter(|f| dir.join(f).exists()).collect();\n    present.is_empty() || present.len() == expected.len()\n}\nif !typed_state_is_consistent(&[\"app.yaml\", \"verge.yaml\"], &typed_dir) {\n    eprintln!(\"partial typed config state; restore or remove files before migrating\");\n}","typeGuard":null,"tryCatchPattern":"match migration_result {\n    Err(e) if e.to_string().contains(\"partial typed config migration state\") => {\n        // surface existing/missing lists to the user for manual cleanup\n    }\n    other => other?,\n}","preventionTips":["Make migration file writes atomic: write to temp files and rename only after all files succeed","Keep a backup of the config directory before running migrations","Never hand-delete individual typed config files; use the app's reset/cleanup function","Log each file written during migration so partial states are diagnosable"],"tags":["config","migration","file-state","consistency"],"backgroundTag":"invalid-state-transition","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"}