libnyanpasu/clash-nyanpasu · error

journal destination is not a regular file: {}

Error message

journal destination is not a regular file: {}

What it means

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.

Source

Thrown at backend/tauri/src/service/profile_file.rs:1232

            let _ = journal;
            Self::rename_journal_same_filesystem(source, destination)
        }
    }

    fn transition_journal(
        root: &Path,
        operation_id: &str,
        from: JournalLocation,
        to: JournalLocation,
    ) -> anyhow::Result<()> {
        let source = Self::journal_path(root, from, operation_id);
        let destination = Self::journal_path(root, to, operation_id);
        let source_journal = Self::read_journal(&source, operation_id)?;
        match std::fs::symlink_metadata(&destination) {
            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
                Self::advance_journal_phase(&source, &destination, &source_journal)
            }
            Ok(metadata) if is_symlink_or_reparse(&metadata) || !metadata.is_file() => bail!(
                "journal destination is not a regular file: {}",
                destination.display()
            ),
            Ok(_) => {
                if Self::read_journal(&destination, operation_id)? != source_journal {
                    bail!("journal destination has a different payload");
                }
                Self::remove_private_regular(&source)
            }
            Err(error) => Err(error).context("inspect journal destination"),
        }
    }

    fn transition_cleanup_journal(
        root: &Path,
        operation_id: &str,
        from: CleanupPhase,
        to: CleanupPhase,

View on GitHub (pinned to f7dbce2997)

Solutions

  1. 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.
  2. Check for cloud-sync/backup interference in the profiles' private journal directory and exclude it from syncing.
  3. Discard the whole interrupted operation by removing all journal files for that operation_id, then re-run the materialization from scratch.
  4. If this recurs on Windows, scan for reparse-point placeholders produced by OneDrive 'files on demand' and make the profiles directory locally available.

Example fix

// before: blindly retrying the transition keeps failing
transition_journal(root, id, JournalLocation::Staged, JournalLocation::Committed)?;
// after: clear the bogus destination artifact first
let dest = journal_path(root, JournalLocation::Committed, &id);
let meta = std::fs::symlink_metadata(&dest)?;
if meta.is_symlink() || !meta.is_file() {
    std::fs::remove_file(&dest)?; // or remove_dir_all for a directory
}
transition_journal(root, id, JournalLocation::Staged, JournalLocation::Committed)?;
Defensive patterns

Strategy: try-catch

Validate before calling

fn journal_destination_ok(root: &Path, to: JournalLocation, id: &str) -> bool {
    match std::fs::symlink_metadata(journal_path(root, to, id)) {
        Err(e) => e.kind() == std::io::ErrorKind::NotFound,
        Ok(m) => !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 transition_journal(root, id, from, to) {
    Err(e) if e.to_string().contains("journal destination is not a regular file") => {
        // remove the foreign artifact, then retry once
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/e96066c85e206ae6. Report an issue: GitHub.