denoland/deno · critical
desktop mode enabled
Error message
desktop mode enabled
What it means
BrowserWindow is Deno's desktop API class, implemented in runtime/ops/desktop.rs. Its constructor fetches Arc<dyn DesktopApi> from OpState with expect("desktop mode enabled"); that state is only installed by the desktop runtime (cli/rt_desktop, used by `deno desktop` / `deno compile --desktop`). Constructing BrowserWindow under plain `deno run` panics in native code and aborts the process — the panic cannot be caught with JS try/catch.
Source
Thrown at runtime/ops/desktop.rs:760
}
}
struct EventTargetSetup {
brand: v8::Global<v8::Value>,
set_event_target_data: v8::Global<v8::Value>,
}
#[op2]
impl BrowserWindow {
#[constructor]
fn new(
state: &OpState,
scope: &mut v8::PinScope<'_, '_>,
#[scoped] options: Option<BrowserWindowOptions>,
) -> v8::Global<v8::Value> {
let api = state
.try_borrow::<Arc<dyn DesktopApi>>()
.expect("desktop mode enabled")
.clone();
// Use the initial window if this is the first BrowserWindow,
// otherwise create a new one.
let window_id = state
.try_borrow::<InitialWindowId>()
.and_then(|iw| iw.0.lock().unwrap().take())
.unwrap_or_else(|| {
let width = options.as_ref().and_then(|o| o.width).unwrap_or(800);
let height = options.as_ref().and_then(|o| o.height).unwrap_or(600);
let frameless =
options.as_ref().and_then(|o| o.frameless).unwrap_or(false);
let no_activate = options
.as_ref()
.and_then(|o| o.no_activate)
.unwrap_or(false);
let transparent_titlebar = options
.as_ref()View on GitHub (pinned to f7822238ca)
Solutions
- Run the app through the desktop runtime: `deno desktop <entry>` during development, or build with `deno compile --desktop` and run the produced binary.
- Move `new BrowserWindow(...)` behind an explicit entry point used only by the desktop app, not into shared/imported modules with side effects.
- Gate desktop construction with a runtime flag you control (e.g. a global set only in the desktop entry) so tests and CLI builds never reach the constructor.
- For unit tests, mock/inject the window factory instead of constructing the real class.
Example fix
// before (runs under `deno run` -> panic: desktop mode enabled)
export const win = new BrowserWindow({ width: 800, height: 600 });
// after: construct only when launched by the desktop runtime
if (globalThis.__DESKTOP_ENTRY__) {
const win = new BrowserWindow({ width: 800, height: 600 });
} Defensive patterns
Strategy: validation
Validate before calling
// set this only in the desktop entry, before importing shared modules
globalThis.__DESKTOP_ENTRY__ = true;
// shared module
if (globalThis.__DESKTOP_ENTRY__) {
const win = new BrowserWindow({ width: 800, height: 600 });
} Type guard
const isDesktopRuntime = () => globalThis.__DESKTOP_ENTRY__ === true;
Prevention
- Only construct BrowserWindow in processes launched by `deno desktop` or built with `deno compile --desktop`.
- Never construct windows at module top level in shared code; defer to an init function in the desktop entry.
- Remember this failure is a Rust panic — JS try/catch cannot intercept it, so prevention is the only defense.
When it happens
Trigger: `new BrowserWindow({ width: 800, height: 600 })` executed in a normal `deno run main.ts` process (or any non-desktop runtime like `deno eval`, `deno test`, `deno serve`), typically because shared code imported by a desktop app was also executed outside it.
Common situations: Importing a module that creates the window at top level into a test or a server build; running the desktop entry with `deno run` during development instead of `deno run` under the desktop runtime; unit tests importing component modules that instantiate windows; code shared between CLI and desktop targets.
Related errors
- failed to spawn desktop runtime thread
- pledge test permissions called before restoring previous ple
- restore test permissions token does not match the stored tok
- pledge test permissions called before restoring previous ple
- restore test permissions token does not match the stored tok
AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20).
Data as JSON: /api/errors/6db2db6515254908.
Report an issue: GitHub.