emilk/egui · error
should have a Window
Error message
should have a Window
What it means
now_sec in eframe's web module calls web_sys::window(), which returns None when there is no global Window object, and panics with 'should have a Window'. This function is only valid inside a browser (WASM) context where a window exists.
Source
Thrown at crates/eframe/src/web/mod.rs:105
}
/// Focus the given element without scrolling it into view.
///
/// Scrolling the element into view would scroll the whole page when
/// the app is embedded in a larger scrollable page,
/// see <https://github.com/emilk/egui/issues/8295>.
pub(crate) fn focus_without_scroll(element: &web_sys::HtmlElement) -> Result<(), JsValue> {
let options = web_sys::FocusOptions::new();
options.set_prevent_scroll(true);
element.focus_with_options(&options)
}
/// Current time in seconds (since undefined point in time).
///
/// Monotonically increasing.
pub fn now_sec() -> f64 {
web_sys::window()
.expect("should have a Window")
.performance()
.expect("should have a Performance")
.now()
/ 1000.0
}
/// The native GUI scale factor, taking into account the browser zoom.
///
/// Corresponds to [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) in JavaScript.
pub fn native_pixels_per_point() -> f32 {
let pixels_per_point = web_sys::window().unwrap().device_pixel_ratio() as f32;
if pixels_per_point > 0.0 && pixels_per_point.is_finite() {
pixels_per_point
} else {
1.0
}
}
View on GitHub (pinned to 441971a776)
Solutions
- Run the code in a browser main thread context where `window` exists.
- In workers, construct or access a WindowProxy/DedicatedWorkerGlobalScope instead, or avoid eframe's timing helpers there.
- For tests, stub time functions or run tests with wasm-bindgen-test in a browser rather than native test runners.
Example fix
// before let t = eframe::web::now_sec(); // after let t = web_sys::window().map(|w| w.performance().map(|p| p.now() / 1000.0)).flatten().unwrap_or(0.0);
Defensive patterns
Strategy: fallback
Validate before calling
let has_window = js_sys::global().dyn_into::<web_sys::Window>().is_ok();
if !has_window { /* skip now_sec-dependent path */ } Type guard
fn window_available() -> bool { web_sys::window().is_some() } Try / catch
// Panic-based; wrap calls in std::panic::catch_unwind(AssertUnwindSafe(|| eframe::web::now_sec())) if recovery is essential, else guard with window().is_some().
Prevention
- Only call eframe web timing helpers from browser main-thread code.
- Use cfg(target_arch = "wasm32") guards plus a window check before use.
- Run wasm tests via wasm-bindgen-test in a real browser, not native test harnesses.
When it happens
Trigger: Calling eframe web code (now_sec directly, or indirectly via AppRunner::auto_save_if_needed / save / time tracking) in a non-browser WASM environment such as Node.js, a worker without a window, or running the crate natively.
Common situations: Unit tests running on native targets or in Node; WASM code running in a Web Worker that lacks a global window; accidentally compiling eframe's web backend into a server-side WASM binary.
Understand the failure class
Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.
Related errors
- should have a Performance
- Your app must implement `as_any_mut`, but it doesn't
- Failed to query about WebGL2 context
- ERROR: {msg}
- Failed to save screenshot to {path:?}: {err}
AI-assisted analysis of emilk/egui@441971a776 (2026-09-12).
Data as JSON: /api/errors/f650d2c359b242c9.
Report an issue: GitHub.