FyroxEngine/Fyrox · warning
There's no message sender for shared handle
Error message
There's no message sender for shared handle {}. The object won't be destroyed. What it means
RcUiNodeHandle is a shared handle that, when dropped, sends a Remove widget message back to the UI via a stored message sender so the widget is destroyed. If the sender is None (handle created without a sender), the widget cannot be scheduled for destruction, the node leaks in the UI, and this warning is logged.
Solutions
- Create/clone the shared handle through the API path that supplies a sender so Drop can send WidgetMessage::Remove.
- Send WidgetMessage::Remove manually for the handle if you know the UI instance.
- Verify the UI that owns the widget is still alive when the handle drops; teardown order may invalidate the sender path.
- If leaking is intentional, ignore the warning or manage the widget lifetime explicitly.
Example fix
// before let handle = RcUiNodeHandle::new(node_handle, None); // no sender -> leak on drop // after let handle = RcUiNodeHandle::new(node_handle, Some(ui_sender.clone())); // or, on cleanup: ui.send_message(WidgetMessage::remove(node_handle));
Defensive patterns
Strategy: fallback
Validate before calling
// Before dropping, ensure the widget will be removed
if handle_needs_manual_cleanup {
ui.send_message(WidgetMessage::remove(node_handle));
} Prevention
- Construct RcUiNodeHandle only through APIs that provide a message sender.
- Keep the UI alive as long as shared handles exist.
- Manually send WidgetMessage::Remove when you know the sender is unavailable.
- Watch logs for this warning during teardown to spot leaked widgets.
When it happens
Trigger: Dropping an RcUiNodeHandle whose inner RcUiNodeHandleInner was constructed with sender: None — i.e. the handle was created through an API path that doesn't supply a UiMessage sender, then the last reference is dropped.
Common situations: Storing RcUiNodeHandles taken from widget contexts/builders where no sender is available, then letting the handle drop and noticing the widget still exists in the UI; holding handles across UI teardown so the sender is gone.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- Widget `preview_message` method is already registered!
- Widget `handle_os_event` method is already registered!
- Widget `on_update` method is already registered!
- Window name is empty, wrong widget will be used as a tile…
- Floating window name is empty, wrong widget will be used as…
AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10).
Data as JSON: /api/errors/fde49b8674e5becb.
Report an issue: GitHub.
Appendix: source
Thrown at fyrox-ui/src/lib.rs:405
self.sender = Some(
visitor
.blackboard
.get::<Sender<UiMessage>>()
.expect("Ui message sender must be provided for correct deserialization!")
.clone(),
);
}
Ok(())
}
}
impl Drop for RcUiNodeHandleInner {
fn drop(&mut self) {
if let Some(sender) = self.sender.as_ref() {
let _ = sender.send(UiMessage::for_widget(self.handle, WidgetMessage::Remove));
} else {
Log::warn(format!(
"There's no message sender for shared handle {}. The object \
won't be destroyed.",
self.handle
))
}
}
}
/// Reference counted handle to a widget. It is used to automatically destroy the widget it points
/// to when the reference counter reaches zero. Its main usage in the library is to store handles
/// to context menus that could be shared across multiple widgets.
#[derive(Clone, Default, Visit, Reflect)]
#[reflect(type_uuid = "9111a53b-05dc-4c75-aab1-71d5b1c93311")]
pub struct RcUiNodeHandle(Arc<Mutex<RcUiNodeHandleInner>>);
impl Debug for RcUiNodeHandle {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let handle = self.0.safe_lock().handle;View on GitHub (pinned to 76c91aad8e)