sxyazi/yazi · error

Failed to work on : source of symlink doesn't exist

Error message

Failed to work on {task:?}: source of symlink doesn't exist

What it means

A file task in yazi-scheduler's download worker was dispatched for a file whose `cha.is_orphan()` is true — i.e. the entry is a symlink whose source (target) does not exist. The scheduler refuses to proceed because there is nothing to download/read through a dangling symlink, so it surfaces the task itself in the message.

Solutions

  1. Verify the symlink target exists before queueing the download task
  2. Refresh the directory in the UI so the dangling symlink is marked orphaned and skip it
  3. Recreate or repoint the symlink target, then retry the task
  4. If writing custom plugin code, check `file.cha.is_orphan()` before scheduling downloads

Example fix

// before
self.requeue(task, LOW); // blindly retries orphaned symlink downloads
// after
if cha.is_orphan() {
    self.ops.fail(id, "symlink target missing, skipping");
} else {
    self.requeue(task, LOW);
}
Defensive patterns

Strategy: validation

Validate before calling

if file.cha.is_orphan() {
    eprintln!("skipping {}: symlink target missing", file.urn());
    return;
}
queue_download(file);

Try / catch

match scheduler_result {
    Err(e) if e.to_string().contains("source of symlink doesn't exist") => refresh_and_skip(),
    Err(e) => return Err(e),
    Ok(v) => Ok(v),
}

Prevention

When it happens

Trigger: A download task is created for a symlink entry whose link target was deleted or moved after the task was queued; the worker then evaluates `cha.is_orphan()` on the fetched FileAttrs and returns Err instead of downloading.

Common situations: User queues a symlink for download/copy, then removes the target file before the task runs; remote (SFTP/ultramarine-style) filesystems where the link target vanishes due to network refresh; stale file lists in the UI pointing at deleted targets.

Related errors


AI-assisted analysis of sxyazi/yazi@a541adde4e (2026-09-02). Data as JSON: /api/errors/6afbbf9c98c7d965. Report an issue: GitHub.

Appendix: source

Thrown at yazi-scheduler/src/file/file.rs:342

	pub(crate) async fn trash_do(&self, task: FileInTrash) -> Result<(), FileOutTrash> {
		ctx!(task, engine::trash(&task.target).await)?;
		Ok(self.ops.out(task.id, FileOutTrash::Succ))
	}

	pub(crate) async fn download(&self, task: FileInDownload) -> Result<(), FileOutDownload> {
		let id = task.id;

		super::traverse::<FileOutDownload, _, _, _, _, _>(
			task,
			async |dir| {
				let dir = dir.to_owned();
				tokio::task::spawn_blocking(move || _ = Cwd::ensure(dir.as_url())).await.ok();
				Ok(())
			},
			async |task, cha| {
				Ok(if cha.is_orphan() {
					Err(anyhow!("Failed to work on {task:?}: source of symlink doesn't exist"))?
				} else {
					self.ops.out(id, FileOutDownload::New(cha.len));
					self.requeue(task, LOW);
				})
			},
			|err| {
				self.ops.out(id, FileOutDownload::Deform(err));
			},
		)
		.await?;

		Ok(self.ops.out(id, FileOutDownload::Succ))
	}

	pub(crate) async fn download_do(
		&self,
		mut task: FileInDownload,
	) -> Result<(), FileOutDownloadDo> {

View on GitHub (pinned to a541adde4e)