emilk/egui · warning

ERROR: {msg}

Error message

ERROR: {msg}

What it means

eframe's web logger routes log::Level::Error records to console.warn(format!("ERROR: {msg}")) instead of console.error, because calling console.error crashed browsers (see egui PR #2961). So a JavaScript console line reading "ERROR: ..." is a warning-level console message produced by this fallback — the actual failure is whatever msg contains; the library deliberately downgrades the severity to avoid the crash.

Source

Thrown at crates/eframe/src/web/web_logger.rs:65

        let msg = if let (Some(file), Some(line)) = (record.file(), record.line()) {
            let file = shorten_file_path(file);
            format!("[{}] {file}:{line}: {}", record.target(), record.args())
        } else {
            format!("[{}] {}", record.target(), record.args())
        };

        match record.level() {
            // NOTE: the `console::trace` includes a stack trace, which is super-noisy.
            log::Level::Trace => console::debug(&msg),

            log::Level::Debug => console::debug(&msg),
            log::Level::Info => console::info(&msg),
            log::Level::Warn => console::warn(&msg),

            // Using console.error causes crashes for unknown reason
            // https://github.com/emilk/egui/pull/2961
            // log::Level::Error => console::error(&msg),
            log::Level::Error => console::warn(&format!("ERROR: {msg}")),
        }
    }

    fn flush(&self) {}
}

/// js-bindings for console.log, console.warn, etc
mod console {
    use wasm_bindgen::prelude::*;

    #[wasm_bindgen]
    extern "C" {
        /// `console.trace`
        #[wasm_bindgen(js_namespace = console)]
        pub fn trace(s: &str);

        /// `console.debug`
        #[wasm_bindgen(js_namespace = console)]

View on GitHub (pinned to 441971a776)

Solutions

  1. Treat console lines with the "ERROR: " prefix as real errors when triaging wasm app logs
  2. Find and fix the root cause reported in msg — the prefix line itself is only the transport
  3. Install a custom log implementation (log::set_boxed_logger) if you need console.error or structured error reporting (e.g. forwarding to Sentry)
  4. Check for an updated eframe where the console.error crash (PR #2961) is fixed and the workaround removed
Defensive patterns

Strategy: try-catch

Try / catch

// Intercept error-level logs in wasm before the default web logger:
struct SentryLogger;
impl log::Log for SentryLogger {
    fn enabled(&self, m: &log::Metadata) -> bool { m.level() <= log::Level::Trace }
    fn log(&self, r: &log::Record) {
        if r.level() == log::Level::Error { send_to_sentry(&format!("{}", r.args())); }
        else { console::log_1(&format!("{}", r.args()).into()); }
    }
    fn flush(&self) {}
}
let _ = log::set_boxed_logger(Box::new(SentryLogger));

Prevention

When it happens

Trigger: Any log::error!(...) (or an error-level log from a dependency) executed inside an eframe web/wasm app while this logger is installed — the message is emitted via console.warn with the "ERROR: " prefix rather than console.error.

Common situations: Debugging a wasm eframe app whose console shows ERROR: lines without matching JS error objects (breakpoints on console.error never fire); confusion in error monitoring that filters on console.error and therefore misses these; hitting the original console.error browser crash on older toolchains.

Related errors


AI-assisted analysis of emilk/egui@441971a776 (2026-09-12). Data as JSON: /api/errors/b175660799ef42fe. Report an issue: GitHub.