GraphiteEditor/Graphite · critical

Failed to send generation request

Error message

Failed to send generation request

What it means

NodeGraphExecutor::queue_execution pushes an ExecutionRequest over a std::sync::mpsc channel to the NodeRuntime worker thread that owns the graph evaluator. NodeRuntimeIO::send returns Result<(), String>, and the expect panics when the send fails — which happens exactly when the receiving NodeRuntime thread has terminated (it panicked inside node execution or was dropped during teardown). The editor main thread crashes at the next execution request (any edit or render), so this error is a secondary symptom: the real failure is whatever killed the runtime thread earlier.

Source

Thrown at editor/src/node_graph_executor.rs:125

		let node_executor = Self {
			futures: Default::default(),
			runtime_io: NodeRuntimeIO::with_channels(request_sender, response_receiver),
			node_graph_hash: 0,
			current_execution_id: 0,
			previous_node_to_inspect: Vec::new(),
			gradient_migration: None,
			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);

View on GitHub (pinned to c507b35645)

Solutions

  1. Find the root cause first: reproduce and read the earlier panic from the NodeRuntime thread in logs — fixing that panic removes this error.
  2. Handle the send error instead of expecting: on Err, mark the executor degraded, surface an error message, and optionally respawn the NodeRuntime (replace_node_runtime with fresh channels).
  3. Guard teardown: set a shutting_down flag checked in queue_execution so late requests are dropped instead of sent into a dead channel.
  4. In tests, keep the runtime thread alive for the executor's lifetime or use with_channels with a receiver that is not dropped prematurely.

Example fix

// before
self.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)).expect("Failed to send generation request");

// after
if self.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)).is_err() {
	log::error!("node runtime thread is gone; skipping execution {execution_id}");
}
Defensive patterns

Strategy: fallback

Validate before calling

// NodeRuntimeIO::send already returns Result — check it instead of expecting
if self.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)).is_err() {
	// runtime thread is dead: degrade gracefully, log, optionally respawn via replace_node_runtime
	return execution_id; // skip further execution bookkeeping
}

Try / catch

// Rust: not a caught exception — the expect panics. Prevent by handling the Result:
match self.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)) {
	Ok(()) => {}
	Err(err) => log::error!("node runtime unavailable: {err}"),
}

Prevention

When it happens

Trigger: Any operation that triggers graph re-execution (document edit, transform, frame render) after the NodeRuntime thread has died: runtime_io.send(GraphRuntimeRequest::ExecutionRequest(...)).expect("Failed to send generation request") returns Err (channel disconnected) and panics on the main thread.

Common situations: A node implementation panicking inside the runtime thread (its panic kills the thread, then the next edit crashes here); application shutdown racing a final execution request; tests spawning a NodeGraphExecutor whose runtime was replaced via replace_node_runtime; double initialization dropping the receiver bound to the stored sender.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/ec56b1f791de6696. Report an issue: GitHub.