GraphiteEditor/Graphite · error
Failed to set logger
Error message
Failed to set logger
What it means
init_graphite (the #[wasm_bindgen(start)] entry) installs WasmLog as the process-wide logger via log::set_logger, which fails — and here panics — whenever a logger is already installed. The log crate permits exactly one global logger per process, so a second initialization or a competing logging crate trips this expect.
Source
Thrown at frontend/wrapper/src/lib.rs:47
pub static LOGGER: WasmLog = WasmLog;
thread_local! {
#[cfg(not(feature = "native"))]
pub static EDITOR: Mutex<Option<editor::application::Editor>> = const { Mutex::new(None) };
#[cfg(not(feature = "native"))]
pub static MESSAGE_BUFFER: std::cell::RefCell<Vec<Message>> = const { std::cell::RefCell::new(Vec::new()) };
pub static EDITOR_WRAPPER: Mutex<Option<editor_wrapper::EditorWrapper>> = const { Mutex::new(None) };
pub static PANIC_DIALOG_MESSAGE_CALLBACK: std::cell::RefCell<Option<js_sys::Function>> = const { std::cell::RefCell::new(None) };
}
/// Initialize the backend
#[wasm_bindgen(start)]
pub fn init_graphite() {
// Set up the panic hook
panic::set_hook(Box::new(panic_hook));
// Set up the logger with a default level of debug
log::set_logger(&LOGGER).expect("Failed to set logger");
log::set_max_level(log::LevelFilter::Debug);
}
/// When a panic occurs, notify the user and log the error to the JS console before the backend dies
pub fn panic_hook(info: &panic::PanicHookInfo) {
let info = info.to_string();
// Node graph panics can only originate here when the node graph runs inside this wasm module
#[cfg(feature = "editor")]
{
let backtrace = Error::new("stack").stack().to_string();
if backtrace.contains("DynAnyNode") {
log::error!("Node graph evaluation panicked {info}");
// When the graph panics, the node runtime lock may not be released properly
if editor::node_graph_executor::NODE_RUNTIME.try_lock().is_none() {
unsafe { editor::node_graph_executor::NODE_RUNTIME.force_unlock() };
}View on GitHub (pinned to c507b35645)
Solutions
- Treat the failure as benign: if log::set_logger errors, a logger is already installed and initialization can continue
- Guard installation with std::sync::Once so repeated init_graphite calls are no-ops
- Audit the dependency tree for other logger crates initialized at startup and remove the duplicate
Example fix
// before
log::set_logger(&LOGGER).expect("Failed to set logger");
// after
static LOG_INIT: std::sync::Once = std::sync::Once::new();
LOG_INIT.call_once(|| {
let _ = log::set_logger(&LOGGER);
});
log::set_max_level(log::LevelFilter::Debug); Defensive patterns
Strategy: fallback
Try / catch
match log::set_logger(&LOGGER) {
Ok(()) => {}
Err(_already_set) => debug!("a logger is already installed; keeping it"),
} Prevention
- Initialize logging exactly once per process; wrap the call in std::sync::Once
- Avoid linking two logger backends in one wasm binary
- Configure the dev server to fully reload on wasm changes so HMR cannot double-instantiate the module
When it happens
Trigger: init_graphite running twice, for example hot-module reload re-instantiating the wasm module or the module being imported by two bundles on one page; another crate (wasm_logger, console_log, tracing-wasm) claiming the logger before the wrapper's start function runs.
Common situations: Dev servers with HMR; embedding the editor wasm in multiple places on a page; mixing logging solutions across dependencies in the same binary.
Related errors
- Failed to fetch Wasm binary part (status ${failedResponse.st
- Failed to get canvas context
- Failed to get canvas context
- Failed to draw ellipse
- Failed to transform circle
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/d6665410db08ebe3.
Report an issue: GitHub.