libnyanpasu/clash-nyanpasu · error
runtime candidate path is not a private directory: {path}
Error message
runtime candidate path is not a private directory: {path} What it means
Raised by prepare_private_dir (backend/tauri/src/client/runtime.rs:275) after create_dir_all when the final symlink_metadata shows the path is either still a symlink/reparse point or is not a directory. The runtime store requires a real, private directory to hold exclusive-create candidate files; anything else is rejected to protect file privacy guarantees (0600 files in a 0700 dir).
Source
Thrown at backend/tauri/src/client/runtime.rs:275
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()
}
#[cfg(windows)]
fn is_symlink_or_reparse(metadata: &std::fs::Metadata) -> bool {
use std::os::windows::fs::MetadataExt;
const FILE_ATTRIBUTE_REPARSE_POINT: u32 = 0x400;View on GitHub (pinned to f7dbce2997)
Solutions
- Check what exists at the path (ls -la / dir) and delete the offending file or symlink so a real directory can be created.
- Re-run after removing the file at that path; create_dir_all will then create a proper directory.
- Resolve the process racing on this path (another app instance or sync tool) before retrying.
- Verify app data directory configuration points at a directory, not a file path.
Example fix
// before: a regular file occupies the candidate dir path
// after: remove the file and create the directory
std::fs::remove_file("/app/data/candidates")?;
std::fs::create_dir_all("/app/data/candidates")?; Defensive patterns
Strategy: validation
Validate before calling
let md = std::fs::symlink_metadata(&candidate_path)?;
if !md.is_dir() || md.file_type().is_symlink() {
// clear the way so create_dir_all can build a real directory
std::fs::remove_file(&candidate_path)?;
std::fs::create_dir_all(&candidate_path)?;
} Type guard
fn is_real_directory(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("not a private directory") => {
std::fs::remove_file(path.as_std_path()).ok();
std::fs::create_dir_all(path.as_std_path())?;
store.create_candidate(&bytes).await?
}
Err(e) => return Err(e),
} Prevention
- Ensure no file or symlink occupies the configured candidate dir path at startup
- Run a single app instance or lock the data dir to avoid races replacing the directory
- Validate data-dir layout during bootstrap, before any writes
- Keep the path configuration pointing at a directory, never a file
When it happens
Trigger: create_candidate_with_names, cleanup_stale_candidates, or candidate_collision_retries_with_exclusive_create calls prepare_private_dir; after create_dir_all, the path exists but is a regular file, a symlink, or another non-directory node, or was swapped between the create and the metadata check.
Common situations: A file named like the candidate dir exists at that path so create_dir_all fails silently or the check runs against the file; a race where another process replaced the directory with a symlink; corrupted install where the data dir path collides with a file.
Related errors
- failed to allocate a unique runtime candidate after 16 attem
- runtime candidate directory is a symlink or reparse point: {
- materialization has multiple staged resources
- 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/5b23558073411813.
Report an issue: GitHub.