iced-rs/iced · error
Send event
Error message
Send event
What it means
The winit runtime's event pump asserts that start_send on a channel to the application's event processor succeeds. This fails only when the channel's receiver has been dropped - i.e. the other half of the Proxy/pump pipeline shut down - which iced treats as an unrecoverable internal state violation during process_event.
Source
Thrown at winit/src/lib.rs:269
fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
self.process_event(
event_loop,
Event::EventLoopAwakened(winit::event::Event::AboutToWait),
);
}
}
impl<Message> Runner<Message> {
fn process_event(
&mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
event: Event<Action<Message>>,
) {
if event_loop.exiting() {
return;
}
self.sender.start_send(event).expect("Send event");
loop {
let poll = self.instance.as_mut().poll(&mut self.context);
match poll {
task::Poll::Pending => match self.receiver.try_recv() {
Ok(control) => match control {
Control::ChangeFlow(flow) => {
use winit::event_loop::ControlFlow;
match (event_loop.control_flow(), flow) {
(
ControlFlow::WaitUntil(current),
ControlFlow::WaitUntil(new),
) if current < new => {}
(ControlFlow::WaitUntil(target), ControlFlow::Wait)
if target > Instant::now() => {}
_ => {View on GitHub (pinned to d146509d89)
Solutions
- Avoid sending events/messages after initiating application exit; guard async tasks/subscriptions with a cancellation flag checked on completion.
- Check that tasks spawned via the Proxy don't outlive the program (join/abort them on shutdown).
- Upgrade iced - teardown races in the winit runtime have been fixed across releases.
- If reproducible, capture the exact sequence (exit + pending event) and restructure so the exit is processed via a message rather than directly stopping the loop.
Example fix
// before
self.sender.start_send(event).expect("Send event");
// after (caller-side guard before exiting)
if !exiting {
proxy.send_event(ev).ok();
} Defensive patterns
Strategy: try-catch
Validate before calling
// before sending from a task, check the program is still running
if app_is_running.load(std::sync::atomic::Ordering::Relaxed) {
proxy.send_event(ev).ok();
} Try / catch
// treat send failure as shutdown, not a crash
match sender.start_send(event) {
Ok(()) => { /* continue */ }
Err(_) => return, // receiver gone: event loop is shutting down
} Prevention
- Abort or join long-running tasks on application exit.
- Use a cancellation flag checked by async subscriptions before sending.
- Prefer sending a shutdown Message over directly stopping the loop.
- Keep iced updated - teardown races are fixed periodically.
When it happens
Trigger: An event (window_event, user_event, new_events, etc.) is dispatched while the receiving side of the mpsc channel (self.receiver's owner) has already been dropped, typically after shutdown/exit began but before the event loop stopped, or from a Proxy send racing application teardown.
Common situations: Sending messages from a subscription/task right as the window closes; programmatic exit() from user code followed by in-flight events; multi-window setups where one window's close tears down the pump while events still arrive.
Related errors
AI-assisted analysis of iced-rs/iced@d146509d89 (2026-09-11).
Data as JSON: /api/errors/e1e1a495a27a5521.
Report an issue: GitHub.