slint-ui/slint · error
{error}
Error message
{error} What it means
PreviewSession::send_to_editor failed while run_with_channels sent the initial RequestState message from the live-preview session to the connected LSP editor. The underlying error (a channel send failure, since PreviewToLsp is backed by an mpsc/channel transport) is stringified and wrapped with anyhow. It means the editor side of the preview protocol is gone or its receiver was dropped before the handshake message could be delivered.
Solutions
- Check that the editor endpoint is still connected and its receiver is alive before starting the preview session; reconnect and re-run.
- Inspect the inner error string produced by send_to_editor to identify whether the transport channel was closed vs. the send failed for another reason.
- Treat this as a fatal session error: shut down the preview loop cleanly and let the editor restart the session, rather than retrying the send.
- If writing tests, keep the editor-side receiver alive for the duration of run_with_channels (e.g. hold the sender or poll the receiver).
Example fix
// before: blindly start the session
run_with_channels(from_editor, to_editor).await?;
// after: bail out early when the editor side is gone
if to_editor.is_closed() {
return Ok(()); // editor already disconnected, nothing to preview
}
run_with_channels(from_editor, to_editor).await?; Defensive patterns
Strategy: try-catch
Validate before calling
// check the transport is still open before starting the session
fn editor_connected(to_editor: &Rc<dyn PreviewToLsp>) -> bool {
!to_editor.is_closed()
} Try / catch
match run_with_channels(from_editor, to_editor).await {
Ok(()) => {},
Err(e) if e.to_string().contains("channel") => {
// editor disconnected during startup: shut down quietly and await a new connection
tracing::warn!("preview session ended: editor channel closed: {e}");
}
Err(e) => return Err(e),
} Prevention
- Always start the preview session after the editor connection is established, not in parallel with it.
- Keep the editor-side receiver alive for the whole session lifetime in tests.
- Handle LspToPreviewMessage::Quit promptly so the session ends before the channel errors out.
- Log the inner send_to_editor error to distinguish disconnects from other transport failures.
When it happens
Trigger: run_with_channels is entered but the editor-side receiver of PreviewToLspMessage is already closed/dropped (editor disconnected, connection teardown raced startup), so the very first PreviewToLspMessage::RequestState send fails.
Common situations: Editor closed the preview connection during startup; the preview process was spawned against a dead transport; the LSP client quit while the preview session was still bootstrapping; unit tests dropping the fake editor channel before calling run_with_channels.
Related errors
- {err}
- Failed to convert path to URL
- File not registered in Live-Preview!
- File not registered in Live-Preview!
- Callbacks were set up earlier
AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16).
Data as JSON: /api/errors/bbfe577edf15bc3e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/live-preview/preview_sessions.rs:480
}
true
}
pub async fn run_with_channels(
mut from_editor: mpsc::UnboundedReceiver<LspToPreviewMessage>,
to_editor: Rc<dyn PreviewToLsp>,
) -> anyhow::Result<()> {
let (event_sender, mut event_receiver) = mpsc::unbounded_channel();
let (preview_session, session_handle) =
PreviewSession::start(to_editor.clone(), move |event| {
event_sender.send(event).ok();
});
preview_session
.send_to_editor(&PreviewToLspMessage::RequestState {
files: Vec::new(),
settings: Vec::new(),
})
.map_err(|error| anyhow::anyhow!(error.to_string()))?;
tokio_spawn_local(async move {
while let Some(message) = from_editor.recv().await {
let should_quit = matches!(message, LspToPreviewMessage::Quit);
if session_handle.handle_message(message).is_err() || should_quit {
break;
}
}
});
install_debug_handler(Rc::downgrade(&to_editor))?;
let mut current_component = None;
let mut component_instance = None;
let mut registered_fonts = HashSet::new();
let mut pending_fonts = Vec::new();
while let Some(event) = event_receiver.recv().await {View on GitHub (pinned to bb937076de)