libnyanpasu/clash-nyanpasu · error
pending cleanup journal is not a regular file
Error message
pending cleanup journal is not a regular file
What it means
While locating a cleanup journal, locate_cleanup inspects the Pending phase path with symlink_metadata. If the path exists but is anything other than a plain regular file (symlink, reparse point, directory), it bails: recovery code must not read through or delete foreign filesystem objects. A journal that exists but is not a regular file means external interference in the private journal directory.
Source
Thrown at backend/tauri/src/service/profile_file.rs:1340
.map(|source| source.materialized().file.clone())
})
.collect()
}
fn locate_cleanup(
root: &Path,
operation_id: &str,
) -> anyhow::Result<Option<(CleanupPhase, MaterializationJournal)>> {
if !valid_operation_id(operation_id) {
bail!("invalid profile cleanup operation id");
}
let pending_path = Self::cleanup_path(root, CleanupPhase::Pending, operation_id);
let ready_path = Self::cleanup_path(root, CleanupPhase::Ready, operation_id);
let pending = match std::fs::symlink_metadata(&pending_path) {
Ok(metadata) if !is_symlink_or_reparse(&metadata) && metadata.is_file() => {
Some(Self::read_journal(&pending_path, operation_id)?)
}
Ok(_) => bail!("pending cleanup journal is not a regular file"),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
Err(error) => return Err(error).context("inspect pending cleanup journal"),
};
let ready = match std::fs::symlink_metadata(&ready_path) {
Ok(metadata) if !is_symlink_or_reparse(&metadata) && metadata.is_file() => {
Some(Self::read_journal(&ready_path, operation_id)?)
}
Ok(_) => bail!("ready cleanup journal is not a regular file"),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
Err(error) => return Err(error).context("inspect ready cleanup journal"),
};
match (pending, ready) {
(None, None) => Ok(None),
(Some(journal), None) => Ok(Some((CleanupPhase::Pending, journal))),
(None, Some(journal)) => Ok(Some((CleanupPhase::Ready, journal))),
(Some(pending), Some(ready)) if pending == ready => {
Self::remove_private_regular(&pending_path)?;
Ok(Some((CleanupPhase::Ready, ready)))View on GitHub (pinned to f7dbce2997)
Solutions
- Inspect the reported Pending journal path, remove the non-file artifact, and rerun recovery (a fresh attempt can then be started or the previous one abandoned).
- Exclude the private journal directory from cloud sync, backup, and antivirus scanning.
- If the profiles root may be writable by other users, move it to a user-private location to rule out symlink planting.
- Abandon the operation by clearing all journals/tombstones for that operation_id and re-plan the cleanup.
Example fix
// before: recovery keeps failing on the bogus artifact
let state = locate_cleanup(root, &id)?;
// after: clear the non-regular Pending artifact first
let p = cleanup_path(root, CleanupPhase::Pending, &id);
let meta = std::fs::symlink_metadata(&p)?;
if meta.is_symlink() || !meta.is_file() {
std::fs::remove_file(&p)?; // or remove_dir_all if a directory
}
let state = locate_cleanup(root, &id)?; Defensive patterns
Strategy: validation
Validate before calling
fn pending_journal_clean(root: &Path, id: &str) -> Result<bool, std::io::Error> {
match std::fs::symlink_metadata(cleanup_path(root, CleanupPhase::Pending, id)) {
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(true),
Err(e) => Err(e),
Ok(m) => Ok(!m.is_symlink() && m.is_file()),
}
} Type guard
fn is_plain_file(m: &std::fs::Metadata) -> bool {
!m.is_symlink() && m.is_file()
} Try / catch
match locate_cleanup(root, id) {
Err(e) if e.to_string().contains("pending cleanup journal is not a regular file") => {
// remove the artifact, then either retry recovery or abandon the operation
}
other => other,
} Prevention
- Exclude journal directories from cloud-sync placeholder features
- Keep the profiles root user-private to prevent symlink planting
- Inspect and remove foreign artifacts before running recovery
- If interference recurs, audit which external tool touches the directory
When it happens
Trigger: Running cleanup lookup/recovery for an operation whose Pending cleanup journal path exists as a symlink, Windows reparse point, or directory — caused by cloud-sync placeholders, quarantine stubs, or manual tampering with the journal directory.
Common situations: OneDrive/Dropbox converting stale journal files to on-demand placeholders on Windows; antivirus replacing the file after quarantine; a developer creating a directory at that path while debugging; symlink attacks if the profiles root is on a shared/writable location.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- ready cleanup journal is not a regular file
- cleanup journal destination is not a regular file: {}
- runtime candidate directory is a symlink or reparse point: {
- profile directory is a symlink, reparse point, or non-direct
- materialization journal is not a regular file: {}
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/35343ccbe1dc04e8.
Report an issue: GitHub.