spacedriveapp/spacedrive · error

System channel closed trying to report working

Error message

System channel closed trying to report working

What it means

SystemComm::working_report (crates/task-system/src/system.rs:452) spawns a detached Tokio task that sends SystemMessage::WorkingReport into the system's bounded(8) message channel; the .expect at system.rs:459 panics when that channel is closed, i.e. every receiver is gone. The receiver is the system message loop spawned in System::new (system.rs:73-97), which exits only after System::shutdown's ShutdownRequest is processed or the Tokio runtime is torn down. The library treats 'system channel closed while a worker still reports' as an invariant violation, so it panics inside the detached task instead of returning an error.

Source

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

		spawn(
			async move {
				system_tx
					.send(SystemMessage::IdleReport(worker_id))
					.await
					.expect("System channel closed trying to report idle");
			}
			.in_current_span(),
		);
	}

	pub fn working_report(&self, worker_id: usize) {
		let system_tx = self.0.clone();
		spawn(
			async move {
				system_tx
					.send(SystemMessage::WorkingReport(worker_id))
					.await
					.expect("System channel closed trying to report working");
			}
			.in_current_span(),
		);
	}

	pub fn pause_not_running_task(
		&self,
		task_id: TaskId,
		task_work_table: Arc<TaskWorktable>,
		ack: oneshot::Sender<Result<(), SystemError>>,
	) {
		let system_tx = self.0.clone();
		spawn(
			async move {
				system_tx
					.send(SystemMessage::PauseNotRunningTask {
						task_id,
						task_work_table,

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Quiesce first: await every TaskHandle, then system.shutdown().await to completion, and only then drop the runtime / end the test
  2. Keep the System alive for the whole process inside one long-lived Tokio runtime instead of per-thread or short-lived runtimes
  3. Avoid issuing dispatch/control operations concurrently with System::shutdown()
  4. Library fix: add the same has_shutdown guard BaseDispatcher::dispatch_boxed uses (system.rs:629) to SystemComm methods, and log/return an error instead of .expect

Example fix

// before
let rt = tokio::runtime::Runtime::new().unwrap();
let system = rt.block_on(async { System::<MyErr>::new() });
drop(system);
drop(rt); // workers' spawned tasks still alive; working_report panics during teardown

// after
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
    let system = System::<MyErr>::new();
    let handles = system.dispatch_many(tasks).await?;
    let _ = futures_util::future::join_all(handles).await; // quiesce workers
    system.shutdown().await; // message loop drains and exits cleanly
});
drop(rt);
Defensive patterns

Strategy: validation

Validate before calling

// Prove the system is quiesced BEFORE teardown drops the runtime.
use futures_util::future::join_all;

let handles = system.dispatch_many(tasks).await?; // or collect as you dispatch
let _ = join_all(handles).await;                   // 1. every worker idle, no reports in flight
system.shutdown().await;                           // 2. message loop drains and exits
// 3. only now may the #[tokio::test] end / the Runtime be dropped

Try / catch

This panic occurs inside a detached Tokio task, so call-site catch_unwind cannot intercept it. Register a logging panic hook (std::panic::set_hook) to capture which task-system sender panicked, and correct the shutdown ordering instead.

Prevention

When it happens

Trigger: A worker reports it is working while System::shutdown() has already been processed (or races with it), so the system loop's receiver is dropped; or the Tokio runtime owning the System is dropped while workers are alive. No public API calls working_report directly; it fires from worker internals (idle/working transitions).

Common situations: Daemon or app exit paths that drop the Tokio runtime before quiescing the task system; #[tokio::test] tests that return while background workers still run; calling System::shutdown() concurrently with dispatch or control traffic.

Related errors


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