libnyanpasu/clash-nyanpasu · error
materialization operation has mixed transaction families
Error message
materialization operation has mixed transaction families
What it means
converge_materialization_journals found journals for the same operation id in multiple transaction-family locations, and not all of them belong to the same family. Each journal location belongs to a transaction family; mixing families means journals from different protocol generations or transaction types coexist for one id, which cannot be safely ordered, so it aborts.
Source
Thrown at backend/tauri/src/service/profile_file.rs:1154
return Err(error)
.with_context(|| format!("inspect journal {}", path.display()));
}
}
}
Self::converge_materialization_journals(found)
}
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`: itsView on GitHub (pinned to f7dbce2997)
Solutions
- Determine which family is current for this app version and remove the foreign-family journals for this operation id, then rerun reconcile.
- Roll the operation back with a manual cleanup of all its journals/staged files and re-materialize with a new operation id.
- Avoid restoring staging directories from backups made by different app versions; only restore profiles, not journals.
- If this follows a version downgrade, upgrade back or clean the staging root before using the service.
Example fix
// before
// journals from two transaction families exist for one operation id
// after
for path in foreign_family_journal_paths(root, operation_id) {
std::fs::remove_file(path)?; // keep only current family
}
client.reconcile(root).await?; Defensive patterns
Strategy: try-catch
Validate before calling
// before resuming, ensure all journals for this op belong to one family
let families: HashSet<_> = existing_journal_families(root, op_id).into_iter().collect();
if families.len() > 1 {
// remove journals of the obsolete family or compensate from scratch
remove_foreign_family_journals(root, op_id, current_family)?;
} Try / catch
match client.reconcile(root).await {
Err(e) if e.to_string().contains("mixed transaction families") => {
// unrecoverable automatically: purge this op and re-materialize
purge_operation(root, op_id)?;
let fresh = client.allocate_operation_id(root).await?;
/* start over */
bail!("operation reset due to mixed journal families")
}
r => r,
} Prevention
- Don't restore journal/staging directories from backups made by different app versions.
- Complete or compensate in-flight operations before upgrading/downgrading the app.
- Never copy operation ids across transaction types.
- On version migration, migrate or clear the staging root explicitly.
When it happens
Trigger: The same operation_id has journal files under locations of different JournalLocation::ALL families — e.g. journals copied between app versions with different layouts, or an operation id reused across transaction families.
Common situations: Upgrading/downgrading the app while an operation was mid-flight; manually copying staging state between installations; restoring backups that mix journal layouts.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- ready symlink path is occupied by an unexpected node
- materialization operation has conflicting journal payloads i
- journal source is not a regular file: {}
- materialization journal not found for operation {operation_i
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/3dd6b6d049cff234.
Report an issue: GitHub.