GraphiteEditor/Graphite · critical
Failed to send editor preferences
Error message
Failed to send editor preferences
What it means
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.
Source
Thrown at editor/src/node_graph_executor.rs:133
gradient_migration_attempted: HashSet::new(),
};
(node_runtime, node_executor)
}
/// Execute the network by flattening it and creating a borrow stack.
fn queue_execution(&mut self, render_config: RenderConfig) -> u64 {
let execution_id = self.current_execution_id;
self.current_execution_id += 1;
let request = ExecutionRequest { execution_id, render_config };
self.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)).expect("Failed to send generation request");
execution_id
}
pub fn update_editor_preferences(&self, editor_preferences: EditorPreferences) {
self.runtime_io
.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences))
.expect("Failed to send editor preferences");
}
/// Updates the network to monitor all inputs. Useful for the testing.
#[cfg(test)]
pub(crate) fn update_node_graph_instrumented(&mut self, document: &mut DocumentMessageHandler) -> Result<Instrumented, String> {
// We should always invalidate the cache.
self.node_graph_hash = crate::application::generate_uuid();
let mut network = document.network_interface.document_network().clone();
let instrumented = Instrumented::new(&mut network);
let resources = document.resources.registry.clone();
self.runtime_io
.send(GraphRuntimeRequest::GraphUpdate(GraphUpdate {
network,
resources,
node_to_inspect: Vec::new(),
}))View on GitHub (pinned to c507b35645)
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.
Example fix
// before
self.runtime_io
.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences))
.expect("Failed to send editor preferences");
// after
if self.runtime_io.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences)).is_err() {
log::warn!("node runtime unavailable; editor preferences not pushed");
} Defensive patterns
Strategy: fallback
Validate before calling
if self.runtime_io.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences)).is_ok() {
// preferences will be applied by the runtime
} else {
// runtime gone: keep local state; re-push when a runtime is recreated
} Try / catch
if let Err(err) = self.runtime_io.send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences)) {
log::warn!("editor preferences not delivered: {err}");
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to send generation request
- Failed to send response
- Star node can't be found
- Brush node does not exist
- Path node does not exist
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/42640b411c79816f.
Report an issue: GitHub.