libnyanpasu/clash-nyanpasu · error
ready symlink path is occupied by an unexpected node
Error message
ready symlink path is occupied by an unexpected node
What it means
create_ready_link found a node at the ready symlink path that is not a symlink (regular file, directory, etc.). The staging protocol requires that path to be either a correct symlink or absent; anything else indicates corruption or external interference, so the operation aborts.
Source
Thrown at backend/tauri/src/service/profile_file.rs:886
target: ExternalProfilePath::new(target)?,
}));
}
Ok(None)
}
fn create_ready_link(
root: &Path,
operation_id: &str,
target: &ExternalProfilePath,
) -> anyhow::Result<PathBuf> {
let ready = Self::ready_link_path(root, operation_id);
match std::fs::symlink_metadata(&ready) {
Ok(metadata) if metadata.file_type().is_symlink() => {
if std::fs::read_link(&ready)? != target.as_path() {
bail!("ready symlink target mismatch");
}
}
Ok(_) => bail!("ready symlink path is occupied by an unexpected node"),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
create_file_symlink(target.as_path(), &ready)
.with_context(|| format!("create staged symlink {}", ready.display()))?;
sync_directory(ready.parent().expect("ready symlink has parent"))?;
}
Err(error) => return Err(error).context("inspect ready symlink"),
}
Ok(ready)
}
fn promote_resource(
&self,
root: &Path,
operation_id: &str,
target: &Path,
expected_hash: &str,
) -> anyhow::Result<()> {
self.ensure_managed_parent(target)?;View on GitHub (pinned to f7dbce2997)
Solutions
- Remove the foreign node at the ready path (after confirming it is not user data) and rerun the materialization.
- Run the journal compensate/reconcile flow to reset the operation's staged state.
- Check the filesystem supports symlinks (Windows developer mode / not a FAT or network share) if this recurs.
- Verify no other process or backup tool is writing into the staging directory.
Example fix
// before // ready path holds a regular file left by a backup tool // after std::fs::remove_file(&ready_path)?; // after verifying contents client.promote(root, operation_id).await?;
Defensive patterns
Strategy: try-catch
Validate before calling
if let Ok(meta) = std::fs::symlink_metadata(&ready_path) {
if !meta.file_type().is_symlink() {
// occupied by a non-symlink node: clean up before calling
std::fs::remove_file(&ready_path)?;
}
} Type guard
fn is_symlink_node(p: &Path) -> bool {
std::fs::symlink_metadata(p).map(|m| m.file_type().is_symlink()).unwrap_or(false)
} Try / catch
match create_ready_link(root, &target) {
Err(e) if e.to_string().contains("unexpected node") => {
let _ = std::fs::remove_file(Self::ready_link_path(root, &op_id));
create_ready_link(root, &target)
}
r => r,
} Prevention
- Exclude the staging root from backup/sync tools that dereference symlinks.
- Use a filesystem that supports symlinks (enable Windows symlink privileges).
- Keep staging directories user-private to avoid foreign writes.
- Run reconcile periodically to clear corrupted staging nodes.
When it happens
Trigger: A ready symlink path is occupied by a non-symlink node: a regular file or directory was created at ready_link_path(root, operation_id), e.g. by a crash leftover, another tool, or a filesystem that materialized the link as a file.
Common situations: Manual cleanup replaced the symlink with a copy; sync/backup tools dereferenced symlinks into regular files; non-symlink-supporting filesystems (some Windows configs/network mounts) writing plain files.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 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: {}
- private materialization artifact is not a regular file: {}
- staged file is not a regular file
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/c319bfea099d3712.
Report an issue: GitHub.