{"record":{"id":"50c3aa7e36b2f1ba","repo":"GraphiteEditor/Graphite","slug":"function-call-failed","errorCode":null,"errorMessage":"Function call failed","messagePattern":"Function call failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/wrapper/src/native_communication.rs","lineNumber":83,"sourceCode":"pub fn decode_editor_command(data: &[u8]) -> Option<editor::messages::prelude::Message> {\n\tmatch serde_json::from_slice::<crate::EditorCommand>(data) {\n\t\tOk(command) => Some(command.into()),\n\t\tErr(e) => {\n\t\t\tlog::error!(\"Failed to deserialize editor command: {e}\");\n\t\t\tNone\n\t\t}\n\t}\n}\n\npub fn initialize_native_communication() {\n\tlet global = js_sys::global();\n\n\t// Get the function by name\n\tlet func = js_sys::Reflect::get(&global, &JsValue::from_str(\"initializeNativeCommunication\")).expect(\"Function not found\");\n\tlet func = func.dyn_into::<js_sys::Function>().expect(\"Not a function\");\n\n\t// Call it\n\tfunc.call0(&JsValue::NULL).expect(\"Function call failed\");\n}\n\npub fn send_message_to_cef(message: String) {\n\tlet global = js_sys::global();\n\n\t// Get the function by name\n\tlet func = js_sys::Reflect::get(&global, &JsValue::from_str(\"sendNativeMessage\")).expect(\"Function not found\");\n\n\tlet func = func.dyn_into::<js_sys::Function>().expect(\"Not a function\");\n\tlet array = Uint8Array::from(message.as_bytes());\n\tlet buffer = array.buffer();\n\n\t// Call it with argument\n\tfunc.call1(&JsValue::NULL, &JsValue::from(buffer)).expect(\"Function call failed\");\n}\n\n#[cfg(feature = \"editor\")]\npub(crate) use editor::messages::frontend::utility_types::RasterizedImage;","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/frontend/wrapper/src/native_communication.rs#L65-L101","documentation":"After resolving initializeNativeCommunication, the wrapper invokes it with func.call0 and expects success. This panic means the JS function was found and called but its body threw: the bridge exists, yet its internals failed — usually because the native APIs it wraps are unavailable or not ready at call time.","triggerScenarios":"Calling the bridge before the CEF-side native bindings it uses are registered; the function throwing when executed outside its expected host; duplicate initialization hitting a throw-on-second-call path.","commonSituations":"Startup races between wasm start and native host initialization; version mismatch between the wrapper and the native shell; running the bridge in a browser where its internals reference CEF-only objects.","solutions":["Open the browser/CEF console and read the underlying JS exception and stack before the Rust panic obscures it","Make the JS-side bridge idempotent and defensive so double init or missing natives degrade to a log line","Handle the Result from call0: log the error and continue startup instead of panicking"],"exampleFix":"// before\nfunc.call0(&JsValue::NULL).expect(\"Function call failed\");\n\n// after\nif let Err(e) = func.call0(&JsValue::NULL) {\n\terror!(\"initializeNativeCommunication threw: {:?}\", e);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = func.call0(&JsValue::NULL) {\n\terror!(\"initializeNativeCommunication threw: {:?}\", e);\n}","preventionTips":["Initialize the native side fully before loading the editor wasm","Wrap bridge function bodies in try/catch on the JS side and expose a readiness flag","Keep wrapper and native shell versions in lockstep to avoid throwing bridge internals"],"tags":["cef","js-interop","call0"],"backgroundTag":"js-bridge-invocation-failed","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}