a-b-street/abstreet · error · anyhow::Error
channel canceled
Error message
channel canceled
What it means
FileLoaded wraps a channel receiver; in its event handler, try_recv failing means the sender (the fetch worker thread) was dropped or the channel closed unexpectedly instead of delivering Ok/None. The library formats 'channel canceled' and invokes on_load with the error, after logging the underlying TryRecvError.
Solutions
- Check the prior 'channel failed: {:?}' log line for the real TryRecvError cause
- Look for panics in the fetch callback (e.g. unwrap on send) and handle them gracefully
- Ensure the loader is dropped/recreated together with its producer when navigating
- Retry the load operation
Example fix
// before
let buffer = array.to_vec();
tx.send(Ok(buffer)).unwrap(); // panic here kills the sender -> 'channel canceled'
// after
if let Err(e) = tx.send(Ok(array.to_vec())) {
error!("receiver dropped: {:?}", e);
} Defensive patterns
Strategy: try-catch
Try / catch
match receiver.try_recv() {
Ok(v) => use(v),
Err(std::sync::mpsc::TryRecvError::Empty) => { /* keep waiting */ }
Err(e) => {
error!("channel failed: {:?}", e);
on_load(ctx, app, Err(anyhow!("channel canceled: {:?}", e)));
}
} Prevention
- Replace tx.send(...).unwrap() in producer callbacks with logged error handling
- Keep FileLoader and its producer thread/task in the same lifecycle; drop them together
- Retry the load once on channel failure before surfacing an error
- Check the preceding 'channel failed' log to find the producer-side panic
When it happens
Trigger: The spawning side (thread/future holding the tx sender) panicked or was dropped before sending any result — e.g. tx.send(...).unwrap() panicked inside the fetch callback, or the FileLoader outlived the worker.
Common situations: A panic inside the download callback (bad data, unwrap on a None/Err), the async task being cancelled, or replaying/rewinding such that the loader outlives its producer.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/f860f29b0c7e396e.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/tools/load.rs:387
outer_progress_receiver: Some(outer_progress_receiver),
inner_progress_receiver: Some(inner_progress_receiver),
last_outer_progress: String::new(),
last_inner_progress: String::new(),
})
}
}
impl<A, T> State<A> for FutureLoader<A, T>
where
A: 'static,
T: 'static,
{
fn event(&mut self, ctx: &mut EventCtx, app: &mut A) -> Transition<A> {
match self.receiver.try_recv() {
Err(e) => {
error!("channel failed: {:?}", e);
let on_load = self.on_load.take().unwrap();
on_load(ctx, app, Err(anyhow!("channel canceled")))
}
Ok(None) => {
if let Some(ref mut rx) = self.outer_progress_receiver {
// Read all of the progress that's happened
loop {
match rx.try_next() {
Ok(Some(msg)) => {
self.last_outer_progress = msg;
}
Ok(None) => {
self.outer_progress_receiver = None;
break;
}
Err(_) => {
// No messages
break;
}
}View on GitHub (pinned to 0964f29315)