GraphiteEditor/Graphite · error
The CEF control thread ended without a result
Error message
The CEF control thread ended without a result
What it means
Panic when result_receiver.recv() returns Err after the CEF message loop shuts down. The control thread is expected to send exactly one result over result_sender before ending; recv() fails only when every sender was dropped without a send. Since the thread's panics are explicitly caught and resumed via join/resume_unwind, this panic means the control thread finished its closure without reaching the send — for example the closure exited early because the CEF message loop/browser context was torn down before the requested operation completed.
Source
Thrown at desktop/ui/src/context.rs:93
host.close_browser(1);
}
});
run_on_ui_thread(cef::quit_message_loop);
match result {
Ok(result) => {
let _ = result_sender.send(result);
}
Err(panic) => std::panic::resume_unwind(panic),
}
})
.expect("Failed to spawn the CEF control thread");
cef::run_message_loop();
drop(CONTEXT.take());
cef::shutdown();
if let Err(panic) = control_thread.join() {
std::panic::resume_unwind(panic);
}
result_receiver.recv().expect("The CEF control thread ended without a result")
}
}
pub(crate) fn execute_helper_process() -> std::process::ExitCode {
let args = bootstrap(true);
assert_eq!(args.as_cmd_line().unwrap().has_switch(Some(&"type".into())), 1, "Not a CEF helper process");
let mut app = RenderProcessAppImpl::app();
let code = execute_process(Some(args.as_main_args()), Some(&mut app), std::ptr::null_mut());
std::process::ExitCode::from(code as u8)
}
fn bootstrap(helper: bool) -> Args {
#[cfg(target_os = "macos")]
{
let loader = cef::library_loader::LibraryLoader::new(&std::env::current_exe().unwrap(), helper);
assert!(loader.load());
// LibraryLoader unloads the framework on drop
std::mem::forget(loader);View on GitHub (pinned to c507b35645)
Solutions
- Ensure the CEF context start/stop path is invoked exactly once per process (guard against double shutdown)
- Reproduce with CEF logging enabled (chrome_debug.log) to see how far the control thread got before teardown
- Patch the control-thread closure to send a sentinel/Err result on every early-exit path instead of returning silently
- If it happens after a CEF upgrade, review shutdown-ordering changes between the wrapper and cef::shutdown()
Example fix
// before
result_receiver.recv().expect("The CEF control thread ended without a result")
// after
match result_receiver.recv() {
Ok(result) => result,
Err(_) => {
tracing::error!("CEF control thread ended without a result (context torn down early)");
return;
}
} Defensive patterns
Strategy: fallback
Try / catch
match result_receiver.recv() {
Ok(result) => result,
Err(_) => {
// Control thread exited without sending (context torn down early): treat as abnormal but orderly exit
tracing::error!("CEF control thread ended without a result; assuming early shutdown");
return;
}
} Prevention
- Make the control-thread closure send a result on every exit path, including early teardown
- Guard the CEF context start/stop path against double invocation
- Enable CEF logging during shutdown work to catch teardown-ordering races early
When it happens
Trigger: Requesting a CEF operation (like browser close) while the context is already shutting down, so run_on_ui_thread callbacks never run and the closure returns without sending; calling the control path twice so the second run races shutdown; CEF shutdown ordering changes where cef::shutdown() terminates work still queued on the UI thread.
Common situations: Rapid window close/reopen or double-invocation of shutdown in the desktop UI; CEF version upgrades changing message-loop lifetime semantics; a shutdown race between the winit event loop exiting and the CEF control thread starting its work.
Related errors
- Failed to spawn the CEF control thread
- Failed to connect to the main process bootstrap server
- Failed to send Hello to the main process
- InvalidData
- Failed to parse input type for #[implementation(...)]. Expec
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/20641ef423c5e28f.
Report an issue: GitHub.