{"record":{"id":"20641ef423c5e28f","repo":"GraphiteEditor/Graphite","slug":"the-cef-control-thread-ended-without-a-result","errorCode":null,"errorMessage":"The CEF control thread ended without a result","messagePattern":"The CEF control thread ended without a result","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"desktop/ui/src/context.rs","lineNumber":93,"sourceCode":"\t\t\t\t\t\thost.close_browser(1);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\trun_on_ui_thread(cef::quit_message_loop);\n\t\t\t\tmatch result {\n\t\t\t\t\tOk(result) => {\n\t\t\t\t\t\tlet _ = result_sender.send(result);\n\t\t\t\t\t}\n\t\t\t\t\tErr(panic) => std::panic::resume_unwind(panic),\n\t\t\t\t}\n\t\t\t})\n\t\t\t.expect(\"Failed to spawn the CEF control thread\");\n\t\tcef::run_message_loop();\n\t\tdrop(CONTEXT.take());\n\t\tcef::shutdown();\n\t\tif let Err(panic) = control_thread.join() {\n\t\t\tstd::panic::resume_unwind(panic);\n\t\t}\n\t\tresult_receiver.recv().expect(\"The CEF control thread ended without a result\")\n\t}\n}\n\npub(crate) fn execute_helper_process() -> std::process::ExitCode {\n\tlet args = bootstrap(true);\n\tassert_eq!(args.as_cmd_line().unwrap().has_switch(Some(&\"type\".into())), 1, \"Not a CEF helper process\");\n\tlet mut app = RenderProcessAppImpl::app();\n\tlet code = execute_process(Some(args.as_main_args()), Some(&mut app), std::ptr::null_mut());\n\tstd::process::ExitCode::from(code as u8)\n}\n\nfn bootstrap(helper: bool) -> Args {\n\t#[cfg(target_os = \"macos\")]\n\t{\n\t\tlet loader = cef::library_loader::LibraryLoader::new(&std::env::current_exe().unwrap(), helper);\n\t\tassert!(loader.load());\n\t\t// LibraryLoader unloads the framework on drop\n\t\tstd::mem::forget(loader);","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/desktop/ui/src/context.rs#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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()"],"exampleFix":"// before\nresult_receiver.recv().expect(\"The CEF control thread ended without a result\")\n\n// after\nmatch result_receiver.recv() {\n\tOk(result) => result,\n\tErr(_) => {\n\t\ttracing::error!(\"CEF control thread ended without a result (context torn down early)\");\n\t\treturn;\n\t}\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"match result_receiver.recv() {\n\tOk(result) => result,\n\tErr(_) => {\n\t\t// Control thread exited without sending (context torn down early): treat as abnormal but orderly exit\n\t\ttracing::error!(\"CEF control thread ended without a result; assuming early shutdown\");\n\t\treturn;\n\t}\n}","preventionTips":["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"],"tags":["rust","cef","shutdown-race","channels","ui"],"backgroundTag":"channel-closed-without-message","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}