spacedriveapp/spacedrive · error

System channel closed trying to resume not running task

Error message

System channel closed trying to resume not running task

What it means

In dispatch_resume_not_running_task_request, after the worker replies, the system forwards the result on the caller's oneshot ack channel. ack.send fails (and the spawned task panics) when the requesting side already dropped its receiver, i.e. the caller of resume went away before the answer arrived. The task-system treats these channels as infallible invariants, so a broken invariant aborts the dispatch task and the resume result is lost.

Source

Thrown at crates/task-system/src/system.rs:286

				let first_attempt_worker_id = task_work_table.worker_id();
				workers[first_attempt_worker_id]
					.resume_task(task_id, tx)
					.await;
				let res = rx
					.await
					.expect("Task system channel closed trying to resume not running task");

				if matches!(res, Err(SystemError::TaskNotFound(_))) {
					warn!(
						%first_attempt_worker_id,
						"Failed the first try to resume a not running task, trying again",
					);
					workers[task_work_table.worker_id()]
						.resume_task(task_id, ack)
						.await;
				} else {
					ack.send(res)
						.expect("System channel closed trying to resume not running task");
				}
			}
		}
		.in_current_span(),
	);
	trace!("Task system resumed task");
}

#[instrument(skip(workers, ack, task_work_table))]
fn dispatch_pause_not_running_task_request<E: RunError>(
	workers: &Arc<Vec<Worker<E>>>,
	task_id: TaskId,
	task_work_table: Arc<TaskWorktable>,
	ack: oneshot::Sender<Result<(), SystemError>>,
) {
	spawn(
		{
			let workers: Arc<Vec<Worker<E>>> = Arc::clone(workers);

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Check whether the panic occurs only during shutdown/disconnect races: then the lost ack is benign and the caller is already gone
  2. Find code that drops task-control futures early (timeout wrappers, abort handles) and keep them alive until the ack resolves
  3. Patch the task-system to replace these expects with logged send failures: a dead ack receiver is recoverable, not fatal
  4. Look for a preceding worker panic in the logs: worker death cascades into broken channel invariants

Example fix

// before: expect panics the dispatch task when the caller is gone
ack.send(res).expect("System channel closed trying to resume not running task");

// after: a dropped requester is not fatal
if ack.send(res).is_err() {
    warn!(%task_id, "Resume ack receiver dropped; caller went away");
}
Defensive patterns

Strategy: validation

Validate before calling

// Keep the requesting future alive until the ack arrives; never wrap task control in timeouts
let ack_rx = system.resume(task_id); // returns the oneshot receiver
let res = ack_rx.await; // hold this to completion — dropping early closes the channel
assert!(matches!(res, Ok(_)), "resume must get its ack");

Prevention

When it happens

Trigger: The caller wrapped resume in a timeout/abort and dropped the future before the ack arrived; client disconnects right after requesting resume of a not-running task; shutdown racing an in-flight resume request.

Common situations: UI request with a short timeout cancelling as the system is mid-dispatch; daemon shutdown while task control requests are pending.

Related errors


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