libnyanpasu/clash-nyanpasu · error
materialization journal operation id mismatch
Error message
materialization journal operation id mismatch
What it means
`read_journal` validates that the parsed `MaterializationJournal`'s `operation_id` equals the operation id used to compute the journal path, and that the id passes `valid_operation_id` (a well-formed identifier). A mismatch means the journal file at `<operation_id>.yaml` contains a different or malformed operation id, so it cannot be trusted as the record for this operation. The library refuses to use it to drive recovery.
Source
Thrown at backend/tauri/src/service/profile_file.rs:622
set_private_file_permissions(path)?;
sync_directory(path.parent().expect("journal has parent"))
}
fn read_journal(path: &Path, operation_id: &str) -> anyhow::Result<MaterializationJournal> {
let metadata = std::fs::symlink_metadata(path)
.with_context(|| format!("inspect materialization journal {}", path.display()))?;
if is_symlink_or_reparse(&metadata) || !metadata.is_file() {
bail!(
"materialization journal is not a regular file: {}",
path.display()
);
}
let content = std::fs::read_to_string(path)
.with_context(|| format!("read materialization journal {}", path.display()))?;
let journal: MaterializationJournal = serde_yaml::from_str(&content)
.with_context(|| format!("parse materialization journal {}", path.display()))?;
if journal.operation_id != operation_id || !valid_operation_id(&journal.operation_id) {
bail!("materialization journal operation id mismatch");
}
if journal
.managed_path
.as_path()
.components()
.any(|component| is_materialization_root_name(component.as_os_str()))
{
bail!("materialization journal targets reserved private storage");
}
if journal.hash.len() != 64 || !journal.hash.bytes().all(|byte| byte.is_ascii_hexdigit()) {
bail!("materialization journal hash is invalid");
}
Ok(journal)
}
fn remove_nofollow(path: &Path) -> anyhow::Result<()> {
match std::fs::symlink_metadata(path) {
Ok(metadata) if metadata.is_dir() && !is_symlink_or_reparse(&metadata) => {View on GitHub (pinned to f7dbce2997)
Solutions
- Delete the mismatched journal file `<root>/<location>/<operation_id>.yaml` so the operation is treated as unknown and re-run materialization
- Do not rename or copy journal files; each journal is keyed by its operation id
- If migrating data, use the app's own export/import rather than copying the materialization directory
- Verify the YAML's `operation_id` field matches the file name if you must inspect it manually
Example fix
// before: file staging/journals/def456.yaml containing // operation_id: abc123 mv staging/journals/def456.yaml /tmp/inspect/ // after: let the app recreate a journal for the current operation id # remove mismatched journal, re-run profile materialization
Defensive patterns
Strategy: validation
Validate before calling
fn valid_op_id(id: &str) -> bool {
!id.is_empty() && id.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_')
}
// before trusting a journal file, check name <-> content correspondence:
// file_name stem must equal journal.operation_id and valid_op_id must hold Type guard
fn journal_matches(j: &MaterializationJournal, op_id: &str) -> bool {
j.operation_id == op_id && valid_op_id(&j.operation_id)
} Try / catch
match read_journal(&path, &op_id) {
Err(e) if e.to_string().contains("operation id mismatch") => {
let _ = std::fs::remove_file(&path); // stale/tampered journal; re-run operation
}
Err(e) => return Err(e),
Ok(j) => use_journal(j),
} Prevention
- Never rename or copy journal files between operation ids
- Keep journal file names identical to their operation_id field
- Restore the materialization root only via app-supported backup flows
- Validate operation ids (alphanumeric/-/_) before writing journals
When it happens
Trigger: Calling recovery/commit code paths that call `read_journal(path, operation_id)` where the YAML on disk stores a different `operation_id`, an empty id, or one failing `valid_operation_id` (e.g. containing path separators, `..`, or invalid characters). Typically caused by copying/renaming journal files by hand or leftover journals from a different operation.
Common situations: Manually copying journal YAML files between operation directories; restoring a partial backup of the materialization root where file names and contents no longer correspond; hand-edited journals; stale journals from an aborted upgrade.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- managed profile path uses reserved private storage
- materialization journal hash is invalid
- staged resource is missing and target hash does not match
- promoted target hash mismatch
- Invalid theme color: {}
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/53acfdedf9e3f860.
Report an issue: GitHub.