libnyanpasu/clash-nyanpasu · error
private materialization artifact is not a regular file: {}
Error message
private materialization artifact is not a regular file: {} What it means
`remove_private_regular` deletes artifacts inside the library's private materialization storage (staged files, backups, journals' companions). It first verifies via `symlink_metadata` that the entry is a plain regular file; symlinks, reparse points, directories, or other node types are refused with this error to keep private storage from being manipulated through links (anti-tampering/anti-symlink-attack guard).
Source
Thrown at backend/tauri/src/service/profile_file.rs:661
path.display()
)
}
Ok(_) => {
std::fs::remove_file(path)
.with_context(|| format!("remove profile resource {}", path.display()))?;
sync_directory(path.parent().expect("profile resource has parent"))
}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(error) => {
Err(error).with_context(|| format!("inspect profile resource {}", path.display()))
}
}
}
fn remove_private_regular(path: &Path) -> anyhow::Result<()> {
match std::fs::symlink_metadata(path) {
Ok(metadata) if is_symlink_or_reparse(&metadata) || !metadata.is_file() => {
bail!(
"private materialization artifact is not a regular file: {}",
path.display()
)
}
Ok(_) => {
std::fs::remove_file(path)
.with_context(|| format!("remove private artifact {}", path.display()))?;
sync_directory(path.parent().expect("private artifact has parent"))
}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(error) => {
Err(error).with_context(|| format!("inspect private artifact {}", path.display()))
}
}
}
fn resource_hash(resource: &MaterializationResource) -> String {
match resource {View on GitHub (pinned to f7dbce2997)
Solutions
- Stop symlink Mount of the materialization root; keep it as real directories with regular files
- Delete the offending symlink/directory at the reported path and re-run the operation (artifacts are transient and safe to regenerate)
- If you must relocate storage, use the application's supported data-directory setting rather than symlinks
- Check for sync tools (Dropbox/OneDrive) converting these files and exclude the directory
Example fix
// before: staged artifact replaced by a symlink staging/files/abc123 -> /mnt/bigdisk/abc123 // after rm staging/files/abc123 # let the app recreate a regular file
Defensive patterns
Strategy: validation
Validate before calling
fn private_artifact_is_regular(path: &std::path::Path) -> bool {
match std::fs::symlink_metadata(path) {
Ok(md) => md.is_file() && !md.file_type().is_symlink(),
Err(e) => e.kind() == std::io::ErrorKind::NotFound,
}
} Type guard
fn is_plain_file(md: &std::fs::Metadata) -> bool {
md.is_file() && !md.file_type().is_symlink()
} Try / catch
match cleanup_private_artifact(&path) {
Err(e) if e.to_string().contains("not a regular file") => {
// unlink the symlink/dir entry so the app can recreate a real file
let _ = std::fs::remove_file(&path);
}
Err(e) => return Err(e),
Ok(()) => (),
} Prevention
- Do not symlink the app's private data directories to other disks
- Exclude materialization storage from cloud-sync/placeholder filesystems
- Keep private storage on local, app-writable filesystems
- Use the app's supported data-dir setting instead of link tricks
When it happens
Trigger: Cleanup/rollback code calls `remove_private_regular` on a path under the materialization root where `symlink_metadata` reports a symlink, Windows reparse point, directory, or non-file. E.g. a user symlinked the whole staging dir elsewhere, or a directory exists where a staged artifact should be.
Common situations: Users symlink private storage directories to another disk to save space; cloud-sync tools replacing files with links; corrupted state where a directory was created at an artifact path.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- runtime candidate directory is a symlink or reparse point: {
- profile directory is a symlink, reparse point, or non-direct
- materialization journal is not a regular file: {}
- refusing to write through unexpected symlink or reparse poin
- materialization journal targets reserved private storage
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/a43cfbcbeff83fe4.
Report an issue: GitHub.