spacedriveapp/spacedrive · info · std::io::Error

Operation cancelled

Error message

Operation cancelled

What it means

Returned by the single-file copy loop when ctx.check_interrupt() signals that the job was cancelled mid-transfer. Before returning, the code removes the partial destination file so a later resume never treats truncated data as complete, then returns io::Error with ErrorKind::Interrupted. This is an intentional cancellation path, not corruption or a bug.

Source

Thrown at core/src/ops/files/copy/strategy.rs:903

	let mut last_progress_update = std::time::Instant::now();

	let mut source_hasher = if verify_checksum {
		Some(blake3::Hasher::new())
	} else {
		None
	};

	let mut dest_hasher = if verify_checksum {
		Some(blake3::Hasher::new())
	} else {
		None
	};

	loop {
		if let Err(_) = ctx.check_interrupt().await {
			// Clean up partial file so resume doesn't see corrupted data.
			let _ = fs::remove_file(destination).await;
			return Err(std::io::Error::new(
				std::io::ErrorKind::Interrupted,
				"Operation cancelled",
			));
		}

		let bytes_read = source_file.read(&mut buffer).await?;
		if bytes_read == 0 {
			break;
		}

		let chunk = &buffer[..bytes_read];
		dest_file.write_all(chunk).await?;
		total_copied += bytes_read as u64;

		if let Some(hasher) = &mut source_hasher {
			hasher.update(chunk);
		}
		if let Some(hasher) = &mut dest_hasher {

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Treat ErrorKind::Interrupted as a clean cancel: report 'cancelled' to the user, do not retry automatically
  2. If the cancel was unintended, inspect job logs for who issued the interrupt (user action vs shutdown)
  3. Re-run the copy job; the partial destination was already deleted, so the retry starts clean

Example fix

// before: any error is surfaced as a generic failure
let res = copy_with_strategy(...).await;

// after: distinguish intentional cancellation
match copy_with_strategy(...).await {
    Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
        report.cancelled(); // user-initiated, not a defect
    }
    other => other?,
}
Defensive patterns

Strategy: try-catch

Type guard

fn is_cancellation(err: &std::io::Error) -> bool {
    err.kind() == std::io::ErrorKind::Interrupted
}

Try / catch

match copy_result {
    Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
        // clean cancel: partial file already removed by the strategy
        state.mark_cancelled();
    }
    Err(e) => return Err(e),
    Ok(_) => {}
}

Prevention

When it happens

Trigger: User cancels a copy job from the UI or CLI while bytes are streaming; the job manager aborts the job (shutdown, parent job failure, timeout policy) between chunk reads; daemon restart interrupts active copy jobs.

Common situations: Cancelling a large transfer partway; system shutdown racing an in-flight copy; a workflow's child copy job cancelled because a sibling step failed.

Related errors


AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16). Data as JSON: /api/errors/cc9281abec52eaa6. Report an issue: GitHub.