{"record":{"id":"e96066c85e206ae6","repo":"libnyanpasu/clash-nyanpasu","slug":"journal-destination-is-not-a-regular-file","errorCode":null,"errorMessage":"journal destination is not a regular file: {}","messagePattern":"journal destination is not a regular file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":1232,"sourceCode":"            let _ = journal;\n            Self::rename_journal_same_filesystem(source, destination)\n        }\n    }\n\n    fn transition_journal(\n        root: &Path,\n        operation_id: &str,\n        from: JournalLocation,\n        to: JournalLocation,\n    ) -> anyhow::Result<()> {\n        let source = Self::journal_path(root, from, operation_id);\n        let destination = Self::journal_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                \"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!(\"journal destination has a different payload\");\n                }\n                Self::remove_private_regular(&source)\n            }\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,","sourceCodeStart":1214,"sourceCodeEnd":1250,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L1214-L1250","documentation":"During a crash-recovery journal phase transition (transition_journal), the library moves the transaction journal from one phase location to the next. If the destination path already exists but is a symlink/reparse point or a non-regular file (directory, fifo, etc.) instead of a normal journal file, it refuses to proceed. This guards the atomic journal-directory invariant: something external has placed a non-file artifact where the next journal phase belongs.","triggerScenarios":"Calling any journal transition (e.g. committing a prepared profile materialization) when the destination phase journal path (journal_path(root, to, operation_id)) exists as a symlink or directory — typically because a previous run crashed mid-write and something else (an editor, antivirus quarantine, a sync tool) replaced the artifact, or because a test/manual probe created a directory there.","commonSituations":"Crash recovery after power loss where OneDrive/Dropbox or a backup tool substituted the journal file with a placeholder or reparse point on Windows; a developer manually inspecting the private journal directory and leaving a directory behind; automated cleanup tools that convert stale files into shortcuts.","solutions":["Inspect the path printed in the message and remove or replace the symlink/non-file artifact with nothing (let the library recreate it), then retry the operation.","Check for cloud-sync/backup interference in the profiles' private journal directory and exclude it from syncing.","Discard the whole interrupted operation by removing all journal files for that operation_id, then re-run the materialization from scratch.","If this recurs on Windows, scan for reparse-point placeholders produced by OneDrive 'files on demand' and make the profiles directory locally available."],"exampleFix":"// before: blindly retrying the transition keeps failing\ntransition_journal(root, id, JournalLocation::Staged, JournalLocation::Committed)?;\n// after: clear the bogus destination artifact first\nlet dest = journal_path(root, JournalLocation::Committed, &id);\nlet meta = std::fs::symlink_metadata(&dest)?;\nif meta.is_symlink() || !meta.is_file() {\n    std::fs::remove_file(&dest)?; // or remove_dir_all for a directory\n}\ntransition_journal(root, id, JournalLocation::Staged, JournalLocation::Committed)?;","handlingStrategy":"try-catch","validationCode":"fn journal_destination_ok(root: &Path, to: JournalLocation, id: &str) -> bool {\n    match std::fs::symlink_metadata(journal_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_journal(root, id, from, to) {\n    Err(e) if e.to_string().contains(\"journal destination is not a regular file\") => {\n        // remove the foreign artifact, then retry once\n    }\n    other => other?,\n}","preventionTips":["Exclude the private journal directory from cloud sync, backup, and antivirus tools","Never create files or directories manually inside the journal directory while debugging","On Windows, keep profile folders outside OneDrive 'files on demand' scope","Treat unexpected journal-directory contents as corruption and clear the whole operation"],"tags":["filesystem","symlink","crash-recovery","transactional-journal"],"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"}