libnyanpasu/clash-nyanpasu · error

materialization operation has conflicting journal payloads i

Error message

materialization operation has conflicting journal payloads in {duplicate_location:?}

What it means

After selecting the highest-rank journal, converge_materialization_journals compares each duplicate (lower-rank) journal payload against the preferred one; a mismatch means the same operation has divergent journal contents across locations. Since the code cannot know which payload reflects the true transaction state, it aborts instead of guessing and possibly promoting the wrong data.

Source

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

    fn converge_materialization_journals(
        mut found: Vec<(JournalLocation, MaterializationJournal, PathBuf)>,
    ) -> anyhow::Result<Option<(JournalLocation, MaterializationJournal)>> {
        let Some(family) = found.first().map(|(location, _, _)| location.family()) else {
            return Ok(None);
        };
        if found
            .iter()
            .any(|(location, _, _)| location.family() != family)
        {
            bail!("materialization operation has mixed transaction families");
        }
        found.sort_by_key(|(location, _, _)| location.rank());
        let (location, journal, _) = found
            .pop()
            .expect("non-empty materialization journal set has a preferred phase");
        for (duplicate_location, duplicate_journal, duplicate_path) in found {
            if duplicate_journal != journal {
                bail!(
                    "materialization operation has conflicting journal payloads in {duplicate_location:?}"
                );
            }
            Self::remove_private_regular(&duplicate_path)?;
        }
        Ok(Some((location, journal)))
    }

    /// The journal locations share one private root, so Unix `rename` is an
    /// atomic same-filesystem phase transition. Do not use `move_atomic`: its
    /// hard-link/unlink fallback can leave duplicate phase artifacts.
    #[allow(dead_code)]
    fn rename_journal_same_filesystem(source: &Path, destination: &Path) -> anyhow::Result<()> {
        let metadata = std::fs::symlink_metadata(source)
            .with_context(|| format!("inspect journal source {}", source.display()))?;
        if is_symlink_or_reparse(&metadata) || !metadata.is_file() {
            bail!("journal source is not a regular file: {}", source.display());
        }

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Manually inspect both journal payloads and keep the one matching the actual on-disk state (staged resource, ready link); delete the stale duplicate and rerun reconcile/complete.
  2. If state cannot be determined, remove all journals for the operation id and compensate/re-materialize from scratch.
  3. Ensure staging lives on a filesystem with atomic rename to avoid the hard-link/unlink fallback path.
  4. Check for crashes correlated with journal phase transitions; UPS/graceful shutdown reduces recurrence.

Example fix

// before
// crash left old-phase journal with stale payload alongside new-phase journal
// after
std::fs::remove_file(&stale_duplicate_path)?; // keep highest-rank journal
client.complete(root, operation_id).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// compare duplicate journal payloads before resuming
let payloads = read_all_journal_payloads(root, op_id)?;
if payloads.iter().any(|p| p != &payloads[0]) {
    // decide from on-disk state which payload is authoritative, delete stale duplicates
}

Try / catch

match client.complete(root, op_id).await {
    Err(e) if e.to_string().contains("conflicting journal payloads") => {
        // cannot auto-resolve: inspect manually or compensate from scratch
        client.compensate(root, op_id).await?;
        let fresh = client.allocate_operation_id(root).await?;
        /* re-materialize */
        bail!("operation rolled back due to conflicting journals")
    }
    r => r,
}

Prevention

When it happens

Trigger: Duplicate journals for one operation id contain different payloads — typically when a same-filesystem rename fell back to hard-link/unlink and a crash left a stale copy of an earlier phase's journal, or journals were partially updated before a crash.

Common situations: Crash/power loss between writing the new-phase journal and removing the old-phase duplicate; filesystems where rename is not atomic; manual copying of journal files between locations.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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