{"record":{"id":"9fe3b0543c41f500","repo":"libnyanpasu/clash-nyanpasu","slug":"ready-cleanup-journal-is-not-a-regular-file","errorCode":null,"errorMessage":"ready cleanup journal is not a regular file","messagePattern":"ready cleanup journal is not a regular file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":1348,"sourceCode":"    ) -> anyhow::Result<Option<(CleanupPhase, MaterializationJournal)>> {\n        if !valid_operation_id(operation_id) {\n            bail!(\"invalid profile cleanup operation id\");\n        }\n        let pending_path = Self::cleanup_path(root, CleanupPhase::Pending, operation_id);\n        let ready_path = Self::cleanup_path(root, CleanupPhase::Ready, operation_id);\n        let pending = match std::fs::symlink_metadata(&pending_path) {\n            Ok(metadata) if !is_symlink_or_reparse(&metadata) && metadata.is_file() => {\n                Some(Self::read_journal(&pending_path, operation_id)?)\n            }\n            Ok(_) => bail!(\"pending cleanup journal is not a regular file\"),\n            Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,\n            Err(error) => return Err(error).context(\"inspect pending cleanup journal\"),\n        };\n        let ready = match std::fs::symlink_metadata(&ready_path) {\n            Ok(metadata) if !is_symlink_or_reparse(&metadata) && metadata.is_file() => {\n                Some(Self::read_journal(&ready_path, operation_id)?)\n            }\n            Ok(_) => bail!(\"ready cleanup journal is not a regular file\"),\n            Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,\n            Err(error) => return Err(error).context(\"inspect ready cleanup journal\"),\n        };\n        match (pending, ready) {\n            (None, None) => Ok(None),\n            (Some(journal), None) => Ok(Some((CleanupPhase::Pending, journal))),\n            (None, Some(journal)) => Ok(Some((CleanupPhase::Ready, journal))),\n            (Some(pending), Some(ready)) if pending == ready => {\n                Self::remove_private_regular(&pending_path)?;\n                Ok(Some((CleanupPhase::Ready, ready)))\n            }\n            (Some(_), Some(_)) => bail!(\"cleanup journals have conflicting payloads\"),\n        }\n    }\n\n    fn has_materialization_journal(root: &Path, operation_id: &str) -> bool {\n        JournalLocation::ALL.iter().any(|location| {\n            std::fs::symlink_metadata(Self::journal_path(root, *location, operation_id)).is_ok()","sourceCodeStart":1330,"sourceCodeEnd":1366,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L1330-L1366","documentation":"Identical guard to the Pending phase, applied to the Ready cleanup journal: if the Ready phase path exists as a symlink/reparse point or non-regular file, locate_cleanup refuses to continue. Recovery requires both phase slots to be either absent or plain regular files so that payloads can be compared safely.","triggerScenarios":"Cleanup lookup/recovery for an operation whose Ready cleanup journal path (cleanup_path(root, CleanupPhase::Ready, operation_id)) exists as a symlink, directory, or Windows reparse point — typically sync-client placeholders or manual/test tampering.","commonSituations":"Crash-recovery run on a machine where OneDrive 'files on demand' turned the Ready journal into a cloud placeholder; CI or scripts leaving directories in the journal folder; security tools substituting files.","solutions":["Delete or replace the non-file artifact at the reported Ready path and rerun the lookup.","Make the journal directory local-only (exclude from cloud sync/space-saver placeholders).","Clear the entire cleanup operation state for that operation_id and restart the cleanup from scratch.","Audit what wrote to the journal directory if this recurs — external tooling is interfering."],"exampleFix":"// before\nlet state = locate_cleanup(root, &id)?; // bails on Ready artifact\n// after\nlet r = cleanup_path(root, CleanupPhase::Ready, &id);\nlet meta = std::fs::symlink_metadata(&r)?;\nif meta.is_symlink() || !meta.is_file() {\n    std::fs::remove_file(&r)?;\n}\nlet state = locate_cleanup(root, &id)?;","handlingStrategy":"validation","validationCode":"fn ready_journal_clean(root: &Path, id: &str) -> Result<bool, std::io::Error> {\n    match std::fs::symlink_metadata(cleanup_path(root, CleanupPhase::Ready, id)) {\n        Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(true),\n        Err(e) => Err(e),\n        Ok(m) => Ok(!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 locate_cleanup(root, id) {\n    Err(e) if e.to_string().contains(\"ready cleanup journal is not a regular file\") => {\n        // clear the non-file Ready artifact, then rerun the lookup\n    }\n    other => other,\n}","preventionTips":["Make journal directories local-only; disable cloud placeholders for them","Never leave test scaffolding in the cleanup phase directory","Clear the full operation state instead of patching individual phase slots","Verify profile folders are not under 'files on demand' management on Windows"],"tags":["filesystem","symlink","cleanup","recovery"],"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-14T05:17:10.506Z"}