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
- 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.
- If state cannot be determined, remove all journals for the operation id and compensate/re-materialize from scratch.
- Ensure staging lives on a filesystem with atomic rename to avoid the hard-link/unlink fallback path.
- 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
- Keep staging on a filesystem with atomic rename to avoid hard-link/unlink duplicates.
- Protect the machine from power loss during profile operations (journaling filesystems, UPS).
- After crashes, always run reconcile before resuming operations.
- Don't manually copy journal files between phase locations.
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
- partial typed config migration state: existing [{}], missing
- materialization operation has mixed transaction families
- journal source is not a regular file: {}
- materialization journal not found for operation {operation_i
- active materialization target diverged before recovery
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/01ff6b3e2da1d842.
Report an issue: GitHub.