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
- Quiesce first: await every TaskHandle, then system.shutdown().await to completion, and only then drop the runtime / end the test
- Keep the System alive for the whole process inside one long-lived Tokio runtime instead of per-thread or short-lived runtimes
- Avoid issuing dispatch/control operations concurrently with System::shutdown()
- 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
- Host the System on one long-lived Tokio runtime; never create it on a runtime you drop early
- Treat System::shutdown as a barrier: no dispatch or control calls until it completes
- Await every TaskHandle before ending a #[tokio::test]
- Run with RUST_LOG=task_system=trace so the last worker report before the panic is visible
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
- System channel closed trying to resume task
- Worker channel closed trying to pause a not running task
- Worker channel closed trying to cancel a not running task
- Worker channel closed trying to force task abortion
- Worker channel closed trying to shutdown
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/aa3a1d015109fc51.
Report an issue: GitHub.