libnyanpasu/clash-nyanpasu · error
materialization has multiple backups
Error message
materialization has multiple backups
What it means
read_backup_resource reads the rollback backup for an operation and expects at most one backup resource (a file blob OR a symlink-spec file) per operation_id under the backup root. Both the backup file path and the backup link path exist, which is an inconsistent state, so the code aborts rather than restoring an ambiguous backup.
Source
Thrown at backend/tauri/src/service/profile_file.rs:854
let link_path = Self::backup_link_path(root, operation_id);
let file_metadata = match std::fs::symlink_metadata(&file_path) {
Ok(metadata) => Some(metadata),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
Err(error) => {
return Err(error)
.with_context(|| format!("inspect backup file {}", file_path.display()));
}
};
let link_metadata = match std::fs::symlink_metadata(&link_path) {
Ok(metadata) => Some(metadata),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
Err(error) => {
return Err(error)
.with_context(|| format!("inspect backup link {}", link_path.display()));
}
};
if file_metadata.is_some() && link_metadata.is_some() {
bail!("materialization has multiple backups");
}
if let Some(metadata) = file_metadata {
if is_symlink_or_reparse(&metadata) || !metadata.is_file() {
bail!("backup file is not a regular file");
}
return Ok(Some(StoredResource::File { path: file_path }));
}
if let Some(metadata) = link_metadata {
if is_symlink_or_reparse(&metadata) || !metadata.is_file() {
bail!("backup symlink specification is not a regular file");
}
let target = std::fs::read_to_string(&link_path)?;
return Ok(Some(StoredResource::Symlink {
target: ExternalProfilePath::new(target)?,
}));
}
Ok(None)
}View on GitHub (pinned to f7dbce2997)
Solutions
- Delete the backup directory contents for this operation_id and re-run the operation so exactly one backup is captured.
- Re-run with a fresh operation_id to get a clean backup area.
- Ensure operation cleanup (removal of backup files) runs after successful promotion, and serialize operations sharing an operation_id.
- If one of the two files is clearly stale (older mtime), remove it — but prefer a clean re-run.
Defensive patterns
Strategy: try-catch
Validate before calling
let f = backup_file_path(root, op_id);
let l = backup_link_path(root, op_id);
if f.exists() && l.exists() {
std::fs::remove_dir_all(backup_dir(root, op_id))?; // clear ambiguous backups
} Try / catch
match result {
Err(e) if e.to_string().contains("multiple backups") => {
clear_backup_dir(root, op_id)?;
retry_with_fresh_operation_id()
}
other => other,
} Prevention
- Use unique operation_ids per materialization run.
- Ensure backup files are cleaned up after successful promotion/rollback.
- Don't merge or manually restore backup directories across operations.
When it happens
Trigger: Both backup_file_path(root, operation_id) and backup_link_path(root, operation_id) exist when read_backup_resource is called — e.g. the same operation_id was used for two materializations where the managed target was first a file and then a symlink, and the earlier backup was never cleaned up.
Common situations: Reused operation IDs across sequential materializations; a failed run that wrote one backup kind, then a retried run wrote the other without cleanup; manual restoration of backup directories merging old and new backups.
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
- materialization has multiple staged resources
- backup file is not a regular file
- backup symlink specification is not a regular file
- failed to allocate a unique runtime candidate after 16 attem
- runtime candidate directory is a symlink or reparse point: {
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/89ef234f6611d11e.
Report an issue: GitHub.