{"record":{"id":"6afbbf9c98c7d965","repo":"sxyazi/yazi","slug":"failed-to-work-on-task-source-of-symlink-does","errorCode":null,"errorMessage":"Failed to work on {task:?}: source of symlink doesn't exist","messagePattern":"Failed to work on (.+?): source of symlink doesn't exist","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"yazi-scheduler/src/file/file.rs","lineNumber":342,"sourceCode":"\n\tpub(crate) async fn trash_do(&self, task: FileInTrash) -> Result<(), FileOutTrash> {\n\t\tctx!(task, engine::trash(&task.target).await)?;\n\t\tOk(self.ops.out(task.id, FileOutTrash::Succ))\n\t}\n\n\tpub(crate) async fn download(&self, task: FileInDownload) -> Result<(), FileOutDownload> {\n\t\tlet id = task.id;\n\n\t\tsuper::traverse::<FileOutDownload, _, _, _, _, _>(\n\t\t\ttask,\n\t\t\tasync |dir| {\n\t\t\t\tlet dir = dir.to_owned();\n\t\t\t\ttokio::task::spawn_blocking(move || _ = Cwd::ensure(dir.as_url())).await.ok();\n\t\t\t\tOk(())\n\t\t\t},\n\t\t\tasync |task, cha| {\n\t\t\t\tOk(if cha.is_orphan() {\n\t\t\t\t\tErr(anyhow!(\"Failed to work on {task:?}: source of symlink doesn't exist\"))?\n\t\t\t\t} else {\n\t\t\t\t\tself.ops.out(id, FileOutDownload::New(cha.len));\n\t\t\t\t\tself.requeue(task, LOW);\n\t\t\t\t})\n\t\t\t},\n\t\t\t|err| {\n\t\t\t\tself.ops.out(id, FileOutDownload::Deform(err));\n\t\t\t},\n\t\t)\n\t\t.await?;\n\n\t\tOk(self.ops.out(id, FileOutDownload::Succ))\n\t}\n\n\tpub(crate) async fn download_do(\n\t\t&self,\n\t\tmut task: FileInDownload,\n\t) -> Result<(), FileOutDownloadDo> {","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/sxyazi/yazi/blob/a541adde4e5b082719a0f21a87eb3eab071ece58/yazi-scheduler/src/file/file.rs#L324-L360","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the symlink target exists before queueing the download task","Refresh the directory in the UI so the dangling symlink is marked orphaned and skip it","Recreate or repoint the symlink target, then retry the task","If writing custom plugin code, check `file.cha.is_orphan()` before scheduling downloads"],"exampleFix":"// before\nself.requeue(task, LOW); // blindly retries orphaned symlink downloads\n// after\nif cha.is_orphan() {\n    self.ops.fail(id, \"symlink target missing, skipping\");\n} else {\n    self.requeue(task, LOW);\n}","handlingStrategy":"validation","validationCode":"if file.cha.is_orphan() {\n    eprintln!(\"skipping {}: symlink target missing\", file.urn());\n    return;\n}\nqueue_download(file);","typeGuard":null,"tryCatchPattern":"match scheduler_result {\n    Err(e) if e.to_string().contains(\"source of symlink doesn't exist\") => refresh_and_skip(),\n    Err(e) => return Err(e),\n    Ok(v) => Ok(v),\n}","preventionTips":["Check is_orphan() before queueing symlink entries","Refresh directory listings after external filesystem changes","Avoid downloading dangling symlinks; resolve targets first"],"tags":["filesystem","symlink","async"],"backgroundTag":"dangling-symlink","analyzedSha":"a541adde4e5b082719a0f21a87eb3eab071ece58","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":"2026-09-02T18:38:25.566Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}