libnyanpasu/clash-nyanpasu · error
ready symlink target mismatch
Error message
ready symlink target mismatch
What it means
During create_ready_link, the staged 'ready' symlink already exists and points to a different path than the ExternalProfilePath supplied for this materialization operation. The function is idempotent: an existing ready symlink with the matching target is accepted, but any divergence means stale or corrupted staging state from another operation, so it aborts rather than promoting the wrong file.
Source
Thrown at backend/tauri/src/service/profile_file.rs:883
}
let target = std::fs::read_to_string(&link_path)?;
return Ok(Some(StoredResource::Symlink {
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,View on GitHub (pinned to f7dbce2997)
Solutions
- Delete the stale ready symlink for this operation_id and rerun the materialization so it is recreated with the current target.
- Run the journal compensate/reconcile flow for this operation_id to clean up inconsistent staged artifacts.
- Generate a fresh operation_id via allocate_operation_id and start the materialization over.
- Inspect the ready symlink target manually (ls -l / fs::read_link) to confirm it belongs to a different operation before removing it.
Example fix
// before // stale ready symlink from a failed run points at old temp file // after // compensate(operation_id) to clear staged artifacts, then re-run promote let _ = client.compensate(root, operation_id).await?; client.promote(root, operation_id).await?;
Defensive patterns
Strategy: retry
Validate before calling
if let Ok(meta) = std::fs::symlink_metadata(&ready_path) {
if meta.file_type().is_symlink() && std::fs::read_link(&ready_path)? != expected_target {
std::fs::remove_file(&ready_path)?; // clear stale link before retry
}
} Type guard
fn ready_link_matches(ready: &Path, target: &Path) -> bool {
std::fs::symlink_metadata(ready)
.map(|m| m.file_type().is_symlink() && std::fs::read_link(ready).map(|p| p == target).unwrap_or(false))
.unwrap_or(false)
} Try / catch
match create_ready_link(root, &target) {
Err(e) if e.to_string().contains("ready symlink target mismatch") => {
let _ = std::fs::remove_file(Self::ready_link_path(root, &op_id));
create_ready_link(root, &target) // retry once after cleanup
}
r => r,
} Prevention
- Always run compensate/reconcile for an operation id before reusing it with new content.
- Never reuse operation ids across materialization attempts; allocate a fresh id each time.
- Don't let external tools touch the staging directory.
- Log the previous symlink target when clearing mismatches to diagnose re-targeting.
When it happens
Trigger: create_ready_link called with a target path while a ready symlink for the same operation_id already exists pointing elsewhere — e.g. a retried operation whose target was regenerated with a different temp path, or an operation_id colliding with a previous run.
Common situations: Re-running a profile download/materialization after a partial failure; reusing an operation id across attempts; manual edits or cleanup tools replacing the ready symlink.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 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/30997032ed007bd0.
Report an issue: GitHub.