sxyazi/yazi · error

Failed to work on: : remote file has changed during upload

Error message

Failed to work on: {task:?}: remote file has changed during upload

What it means

During the final phase of an upload, yazi-scheduler re-hashes the original source file and compares its signature hash against the stamp taken before transfer began. If the hashes differ, the source was modified concurrently, so the scheduler aborts the upload (before renaming the temp file into place) to avoid persisting inconsistent or clobbered data.

Solutions

  1. Stop processes writing to the source file, then retry the upload
  2. Upload a stable snapshot: copy the file to a temp location and upload that
  3. Retry the upload — if the file is now quiescent the hash will match
  4. For continuously-written files (logs), use rotation or flush-then-upload sequencing

Example fix

// before
std::fs::copy("/var/log/app.log", "/tmp/upload-staging")?; // file keeps growing
// after
let snapshot = std::fs::read("/var/log/app.log")?; // take a point-in-time copy
std::fs::write("/tmp/upload-staging", &snapshot)?;
Defensive patterns

Strategy: retry

Validate before calling

// Compare file size/mtime before and after to detect concurrent modification early
let before = std::fs::metadata(path)?;
// ... upload ...
let after = std::fs::metadata(path)?;
assert_eq!(before.len(), after.len(), "file modified during upload");

Try / catch

match upload_result {
    Err(e) if e.to_string().contains("remote file has changed during upload") => {
        backoff_retry(upload, 3);
    }
    other => other,
}

Prevention

When it happens

Trigger: The file being uploaded is modified (written, appended, truncated) by another process or user while the upload loop is still streaming data; the post-transfer hash `stamp.sig()` then mismatches `cha.hash_u128_str()` of the freshly stat'ed source.

Common situations: Editing a file in an editor that writes in-place while it's being uploaded to a remote; log files actively appended to during upload; sync tools or CI scripts touching the same file concurrently.

Related errors


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

Appendix: source

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

			ctx!(task, Transaction::tmp(&task.target).await, "Cannot determine temporary upload path")?;
		let mut rx = ctx!(
			task,
			engine::copy(cache, &tmp, Attrs {
				mode:  Some(cha.mode),
				atime: None,
				btime: None,
				mtime: None,
			})
			.await
		)?;

		loop {
			match rx.recv().await.unwrap_or(Ok(0)) {
				Ok(0) => {
					let cha =
						ctx!(task, Self::cha(&task.target, true, None).await, "Cannot stat original file")?;
					if stamp.sig() != cha.hash_u128_str(&mut [0; 26]) {
						Err(anyhow!("Failed to work on: {task:?}: remote file has changed during upload"))?;
					}

					ctx!(task, engine::rename(&tmp, &task.target).await, "Cannot persist uploaded file")?;

					let cha =
						ctx!(task, Self::cha(&task.target, true, None).await, "Cannot stat uploaded file")?;
					ctx!(task, Stamp::write(cha, task.target.as_url()).await)?;

					break;
				}
				Ok(n) => self.ops.out(task.id, FileOutUploadDo::Adv(n)),
				Err(e) => ctx!(task, Err(e))?,
			}
		}
		Ok(self.ops.out(task.id, FileOutUploadDo::Succ))
	}

	pub(super) async fn cha<U>(url: U, follow: bool, dent: Option<DirEntry>) -> io::Result<Cha>

View on GitHub (pinned to a541adde4e)