{"record":{"id":"f860f29b0c7e396e","repo":"a-b-street/abstreet","slug":"channel-canceled","errorCode":null,"errorMessage":"channel canceled","messagePattern":"channel canceled","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"widgetry/src/tools/load.rs","lineNumber":387,"sourceCode":"            outer_progress_receiver: Some(outer_progress_receiver),\n            inner_progress_receiver: Some(inner_progress_receiver),\n            last_outer_progress: String::new(),\n            last_inner_progress: String::new(),\n        })\n    }\n}\n\nimpl<A, T> State<A> for FutureLoader<A, T>\nwhere\n    A: 'static,\n    T: 'static,\n{\n    fn event(&mut self, ctx: &mut EventCtx, app: &mut A) -> Transition<A> {\n        match self.receiver.try_recv() {\n            Err(e) => {\n                error!(\"channel failed: {:?}\", e);\n                let on_load = self.on_load.take().unwrap();\n                on_load(ctx, app, Err(anyhow!(\"channel canceled\")))\n            }\n            Ok(None) => {\n                if let Some(ref mut rx) = self.outer_progress_receiver {\n                    // Read all of the progress that's happened\n                    loop {\n                        match rx.try_next() {\n                            Ok(Some(msg)) => {\n                                self.last_outer_progress = msg;\n                            }\n                            Ok(None) => {\n                                self.outer_progress_receiver = None;\n                                break;\n                            }\n                            Err(_) => {\n                                // No messages\n                                break;\n                            }\n                        }","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/widgetry/src/tools/load.rs#L369-L405","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet buffer = array.to_vec();\ntx.send(Ok(buffer)).unwrap(); // panic here kills the sender -> 'channel canceled'\n// after\nif let Err(e) = tx.send(Ok(array.to_vec())) {\n    error!(\"receiver dropped: {:?}\", e);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match receiver.try_recv() {\n    Ok(v) => use(v),\n    Err(std::sync::mpsc::TryRecvError::Empty) => { /* keep waiting */ }\n    Err(e) => {\n        error!(\"channel failed: {:?}\", e);\n        on_load(ctx, app, Err(anyhow!(\"channel canceled: {:?}\", e)));\n    }\n}","preventionTips":["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"],"tags":["channels","concurrency","wasm","internal-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}