{"record":{"id":"4a8a5c00a3d5a589","repo":"libnyanpasu/clash-nyanpasu","slug":"cleanup-journal-destination-is-not-a-regular-file","errorCode":null,"errorMessage":"cleanup journal destination is not a regular file: {}","messagePattern":"cleanup journal destination is not a regular file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":1259,"sourceCode":"            }\n            Err(error) => Err(error).context(\"inspect journal destination\"),\n        }\n    }\n\n    fn transition_cleanup_journal(\n        root: &Path,\n        operation_id: &str,\n        from: CleanupPhase,\n        to: CleanupPhase,\n    ) -> anyhow::Result<()> {\n        let source = Self::cleanup_path(root, from, operation_id);\n        let destination = Self::cleanup_path(root, to, operation_id);\n        let source_journal = Self::read_journal(&source, operation_id)?;\n        match std::fs::symlink_metadata(&destination) {\n            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {\n                Self::advance_journal_phase(&source, &destination, &source_journal)\n            }\n            Ok(metadata) if is_symlink_or_reparse(&metadata) || !metadata.is_file() => bail!(\n                \"cleanup journal destination is not a regular file: {}\",\n                destination.display()\n            ),\n            Ok(_) => {\n                if Self::read_journal(&destination, operation_id)? != source_journal {\n                    bail!(\"cleanup journal destination has a different payload\");\n                }\n                Self::remove_private_regular(&source)\n            }\n            Err(error) => Err(error).context(\"inspect cleanup journal destination\"),\n        }\n    }\n\n    fn discard_materialization(\n        root: &Path,\n        operation_id: &str,\n        location: JournalLocation,\n    ) -> anyhow::Result<()> {","sourceCodeStart":1241,"sourceCodeEnd":1277,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L1241-L1277","documentation":"Same guard as the materialization transition, but for the cleanup journal family: transition_cleanup_journal moves a cleanup journal between CleanupPhase locations (e.g. Pending -> Ready). If the destination cleanup-journal path exists as a symlink/reparse point or a non-regular file, the library refuses rather than writing through it. This protects the cleanup recovery path from foreign or hostile artifacts.","triggerScenarios":"Running profile cleanup recovery (transitioning the cleanup journal from Pending to Ready) when cleanup_path(root, to, operation_id) exists as a symlink, directory, or Windows reparse point — e.g. a sync client replaced the file or someone probed the cleanup directory manually.","commonSituations":"Cloud-drive placeholder reparse points on Windows intercepting the cleanup journal path; leftover test scaffolding that created a directory at the cleanup phase path; antivirus quarantining the journal and leaving a stub.","solutions":["Remove the symlink/non-file artifact at the reported destination path and retry the cleanup.","Exclude the profiles private journal directory from cloud sync and antivirus real-time scanning.","Abandon the cleanup by deleting all cleanup journals for that operation_id, then re-plan the cleanup.","On Windows, confirm the path is not under a OneDrive 'files on demand' folder; download contents locally."],"exampleFix":"// before: transition fails repeatedly\ntransition_cleanup_journal(root, &id, CleanupPhase::Pending, CleanupPhase::Ready)?;\n// after: clear the non-file destination first\nlet dest = cleanup_path(root, CleanupPhase::Ready, &id);\nlet meta = std::fs::symlink_metadata(&dest)?;\nif meta.is_symlink() || !meta.is_file() {\n    std::fs::remove_file(&dest)?;\n}\ntransition_cleanup_journal(root, &id, CleanupPhase::Pending, CleanupPhase::Ready)?;","handlingStrategy":"try-catch","validationCode":"fn cleanup_destination_ok(root: &Path, to: CleanupPhase, id: &str) -> bool {\n    match std::fs::symlink_metadata(cleanup_path(root, to, id)) {\n        Err(e) => e.kind() == std::io::ErrorKind::NotFound,\n        Ok(m) => !m.is_symlink() && m.is_file(),\n    }\n}","typeGuard":"fn is_plain_file(m: &std::fs::Metadata) -> bool {\n    !m.is_symlink() && m.is_file()\n}","tryCatchPattern":"match transition_cleanup_journal(root, id, from, to) {\n    Err(e) if e.to_string().contains(\"cleanup journal destination is not a regular file\") => {\n        // remove the foreign artifact at the printed path, retry once\n    }\n    other => other?,\n}","preventionTips":["Keep the cleanup journal directory out of cloud-sync and antivirus scanning","Avoid manual probing that leaves directories in cleanup phase slots","On Windows, force local availability of profile folders under OneDrive","Clear the entire operation state when artifacts look foreign"],"tags":["filesystem","symlink","crash-recovery","cleanup"],"backgroundTag":"incompatible-source-type","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}