{"record":{"id":"42640b411c79816f","repo":"GraphiteEditor/Graphite","slug":"failed-to-send-editor-preferences","errorCode":null,"errorMessage":"Failed to send editor preferences","messagePattern":"Failed to send editor preferences","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"editor/src/node_graph_executor.rs","lineNumber":133,"sourceCode":"\t\t\tgradient_migration_attempted: HashSet::new(),\n\t\t};\n\t\t(node_runtime, node_executor)\n\t}\n\n\t/// Execute the network by flattening it and creating a borrow stack.\n\tfn queue_execution(&mut self, render_config: RenderConfig) -> u64 {\n\t\tlet execution_id = self.current_execution_id;\n\t\tself.current_execution_id += 1;\n\t\tlet request = ExecutionRequest { execution_id, render_config };\n\t\tself.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)).expect(\"Failed to send generation request\");\n\n\t\texecution_id\n\t}\n\n\tpub fn update_editor_preferences(&self, editor_preferences: EditorPreferences) {\n\t\tself.runtime_io\n\t\t\t.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences))\n\t\t\t.expect(\"Failed to send editor preferences\");\n\t}\n\n\t/// Updates the network to monitor all inputs. Useful for the testing.\n\t#[cfg(test)]\n\tpub(crate) fn update_node_graph_instrumented(&mut self, document: &mut DocumentMessageHandler) -> Result<Instrumented, String> {\n\t\t// We should always invalidate the cache.\n\t\tself.node_graph_hash = crate::application::generate_uuid();\n\t\tlet mut network = document.network_interface.document_network().clone();\n\t\tlet instrumented = Instrumented::new(&mut network);\n\n\t\tlet resources = document.resources.registry.clone();\n\n\t\tself.runtime_io\n\t\t\t.send(GraphRuntimeRequest::GraphUpdate(GraphUpdate {\n\t\t\t\tnetwork,\n\t\t\t\tresources,\n\t\t\t\tnode_to_inspect: Vec::new(),\n\t\t\t}))","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/node_graph_executor.rs#L115-L151","documentation":"update_editor_preferences forwards an EditorPreferencesUpdate over the same mpsc request channel to the NodeRuntime thread and expects the send to succeed. The expect fires when the runtime thread no longer exists (it panicked or was torn down), so any preferences change (e.g., theme/performance settings applied mid-session) crashes the main thread. As with the execution-request variant, the channel failure is downstream evidence that the runtime worker died earlier; the send error string is produced by NodeRuntimeIO::send mapping SendError to String.","triggerScenarios":"Changing editor preferences while the NodeRuntime worker thread has already terminated: runtime_io.send(GraphRuntimeRequest::EditorPreferencesUpdate(...)).expect(\"Failed to send editor preferences\") receives a disconnected-channel error and panics.","commonSituations":"A prior runtime-thread panic in node execution followed by any preferences update; shutdown ordering where the runtime is dropped before the final preference sync; tests that construct executors without a live runtime and then call update_editor_preferences.","solutions":["Treat a send failure as 'runtime unavailable': log and skip the update instead of expecting, since preferences can be re-applied when a runtime is recreated.","Diagnose the runtime death: search logs above this panic for the original NodeRuntime panic backtrace and fix that node/thread issue.","Add a shutdown guard so preference pushes are suppressed once teardown begins.","In tests, drive preferences updates through an executor with a live channel pair (with_channels) rather than a dropped receiver."],"exampleFix":"// before\nself.runtime_io\n\t.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences))\n\t.expect(\"Failed to send editor preferences\");\n\n// after\nif self.runtime_io.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences)).is_err() {\n\tlog::warn!(\"node runtime unavailable; editor preferences not pushed\");\n}","handlingStrategy":"fallback","validationCode":"if self.runtime_io.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences)).is_ok() {\n\t// preferences will be applied by the runtime\n} else {\n\t// runtime gone: keep local state; re-push when a runtime is recreated\n}","typeGuard":null,"tryCatchPattern":"if let Err(err) = self.runtime_io.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences)) {\n\tlog::warn!(\"editor preferences not delivered: {err}\");\n}","preventionTips":["Treat preference pushes as retryable state sync, not fire-and-forget expects.","Track last-sent preferences so a respawned runtime can be brought up to date.","Suppress channel traffic once shutdown begins to avoid racing a dying receiver."],"tags":["rust","graphite-editor","mpsc","channel-closed","expect-panic","preferences","node-runtime"],"backgroundTag":"mpsc-channel-closed","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}