libnyanpasu/clash-nyanpasu · error
runtime candidate directory is a symlink or reparse point: {
Error message
runtime candidate directory is a symlink or reparse point: {path} What it means
Raised by prepare_private_dir (backend/tauri/src/client/runtime.rs:270) when symlink_metadata of the runtime candidate directory reports it is a symlink (or Windows reparse point). The store refuses to write private candidate files into a symlinked location because a symlink could redirect sensitive runtime files elsewhere or be swapped mid-operation.
Source
Thrown at backend/tauri/src/client/runtime.rs:270
}
Err(error) => Err(error.into()),
}
}
}
impl Drop for CandidateFile {
fn drop(&mut self) {
if !self.cleaned {
let _ = std::fs::remove_file(&self.path);
}
}
}
async fn prepare_private_dir(path: &Utf8Path) -> anyhow::Result<()> {
if let Ok(metadata) = tokio::fs::symlink_metadata(path).await
&& is_symlink_or_reparse(&metadata)
{
anyhow::bail!("runtime candidate directory is a symlink or reparse point: {path}");
}
tokio::fs::create_dir_all(path).await?;
let metadata = tokio::fs::symlink_metadata(path).await?;
if is_symlink_or_reparse(&metadata) || !metadata.is_dir() {
anyhow::bail!("runtime candidate path is not a private directory: {path}");
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
tokio::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700)).await?;
}
Ok(())
}
#[cfg(unix)]
fn is_symlink_or_reparse(metadata: &std::fs::Metadata) -> bool {
metadata.file_type().is_symlink()
}View on GitHub (pinned to f7dbce2997)
Solutions
- Remove the symlink at the candidate path and let the app create a real directory (passing the real target path explicitly if needed).
- Point the candidate directory configuration at the physical path instead of the symlink.
- On Windows, replace junctions/reparse points created by cloud-sync tools with real directories excluded from syncing.
Example fix
// before (path is a symlink)
let store = RuntimeStore::new(Utf8PathBuf::from("/app/data/candidates-linked"));
// after (real directory)
std::fs::remove_file("/app/data/candidates-linked")?;
std::fs::create_dir("/app/data/candidates")?;
let store = RuntimeStore::new(Utf8PathBuf::from("/app/data/candidates")); Defensive patterns
Strategy: validation
Validate before calling
use std::os::unix::fs::MetadataExt;
let md = std::fs::symlink_metadata(&candidate_path)?;
if md.file_type().is_symlink() {
return Err(anyhow::anyhow!("candidate dir must not be a symlink"));
}
if !md.is_dir() {
return Err(anyhow::anyhow!("candidate path is not a directory"));
} Type guard
fn is_plain_dir(path: &Utf8Path) -> bool {
std::fs::symlink_metadata(path.as_std_path())
.map(|md| md.is_dir() && !md.file_type().is_symlink())
.unwrap_or(false)
} Try / catch
match store.create_candidate(&bytes).await {
Ok(c) => c,
Err(e) if e.to_string().contains("symlink or reparse point") => {
// refuse to proceed; surface a configuration/integrity error to the user
return Err(IntegrityError::SymlinkedCandidateDir.into());
}
Err(e) => return Err(e),
} Prevention
- Never symlink the app data / candidate directory; configure the real physical path instead
- Exclude the data directory from cloud-sync tools that create reparse points (Dropbox, OneDrive)
- Check install scripts and packaging for ln -s or junction creation on data dirs
- Validate the data dir layout at startup and fail fast with a clear message
When it happens
Trigger: create_candidate_with_names, cleanup_stale_candidates, or candidate_collision_retries_with_exclusive_create calls prepare_private_dir while candidate_dir itself is a symlink or reparse point (checked before create_dir_all).
Common situations: User or packaging replaced the app data directory with a symlink to another disk; portable installs with linked config dirs; Windows junction/reparse points created by sync tools (Dropbox, OneDrive).
Related errors
- profile directory is a symlink, reparse point, or non-direct
- materialization journal is not a regular file: {}
- private materialization artifact is not a regular file: {}
- staged file is not a regular file
- staged symlink specification is not a regular file
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/d45d0376a6fb9d74.
Report an issue: GitHub.