{"record":{"id":"9c96ce11e439b687","repo":"tauri-apps/tauri","slug":"window-set-enabled-can-only-be-called-on-the-ma","errorCode":null,"errorMessage":"`Window::set_enabled` can only be called on the main thread","messagePattern":"`Window::set_enabled` can only be called on the main thread","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri-runtime-wry/src/window/macos.rs","lineNumber":17,"sourceCode":"// Copyright 2019-2024 Tauri Programme within The Commons Conservancy\n// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\n\nuse objc2::MainThreadMarker;\nuse objc2_app_kit::{NSBackingStoreType, NSWindow, NSWindowStyleMask};\nuse tao::platform::macos::WindowExtMacOS;\n\nimpl super::WindowExt for tao::window::Window {\n  // based on electron implementation\n  // https://github.com/electron/electron/blob/15db63e26df3e3d59ce6281f030624f746518511/shell/browser/native_window_mac.mm#L474\n  fn set_enabled(&self, enabled: bool) {\n    let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() };\n    if !enabled {\n      let frame = ns_window.frame();\n      let mtm = MainThreadMarker::new()\n        .expect(\"`Window::set_enabled` can only be called on the main thread\");\n      let sheet = unsafe {\n        NSWindow::initWithContentRect_styleMask_backing_defer(\n          mtm.alloc(),\n          frame,\n          NSWindowStyleMask::Titled,\n          NSBackingStoreType::Buffered,\n          false,\n        )\n      };\n      sheet.setAlphaValue(0.5);\n      ns_window.beginSheet_completionHandler(&sheet, None);\n    } else if let Some(attached) = ns_window.attachedSheet() {\n      ns_window.endSheet(&attached);\n    }\n  }\n\n  fn is_enabled(&self) -> bool {\n    let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() };","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/tauri-apps/tauri/blob/52e4b6e71d8632a7e648f866c442e287ecddee34/crates/tauri-runtime-wry/src/window/macos.rs#L1-L35","documentation":"macOS UI APIs are main-thread-only. In tauri-runtime-wry's macOS backend, Window::set_enabled builds the sheet overlay via MainThreadMarker::new().expect(\"`Window::set_enabled` can only be called on the main thread\"); MainThreadMarker::new() returns None when called off the main thread, so invoking set_enabled from any other thread panics.","triggerScenarios":"Calling window.set_enabled(false/true) from a tokio task, std::thread, async command handler, or other non-main thread — e.g. disabling the window while awaiting a long operation — without dispatching to the main thread.","commonSituations":"Porting synchronous window logic to async (spawn(async move { window.set_enabled(false); ... })); calling window APIs from background workers; WebDriver/test harnesses touching windows from helper threads.","solutions":["Dispatch the call to the main thread: window.run_on_main_thread(move || { window.set_enabled(false); }) or app_handle.run_on_main_thread(...)","Restructure so UI mutations happen in main-thread contexts (event handlers, non-async commands)","Guard UI code with a main-thread assertion in debug builds to fail early with a clear message","Audit async blocks that capture window handles for direct API calls"],"exampleFix":"// before\ntauri::async_runtime::spawn(async move {\n  window.set_enabled(false); // panics off-main-thread on macOS\n  do_work().await;\n});\n\n// after\nlet w = window.clone();\nwindow.run_on_main_thread(move || w.set_enabled(false))?;\ntauri::async_runtime::spawn(async move { do_work().await });","handlingStrategy":"type-guard","validationCode":"// call sites guard before touching UI: if !is_main_thread() { window.run_on_main_thread(...)?; }","typeGuard":"use std::sync::OnceLock;\nstatic MAIN_THREAD: OnceLock<std::thread::ThreadId> = OnceLock::new();\npub fn init_main_thread() { MAIN_THREAD.set(std::thread::current().id()).ok(); }\npub fn is_main_thread() -> bool {\n    MAIN_THREAD.get().is_some_and(|id| *id == std::thread::current().id())\n}","tryCatchPattern":null,"preventionTips":["Route every Window/WebviewWindow mutation through run_on_main_thread on macOS","Audit async blocks and background threads that capture window handles","Add debug_assert!(is_main_thread()) inside UI helper functions"],"tags":["macos","window","threading","runtime"],"backgroundTag":"main-thread-only-api","analyzedSha":"52e4b6e71d8632a7e648f866c442e287ecddee34","analyzedAt":"2026-08-20T13:59:20.734Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}