GraphiteEditor/Graphite · error

Custom Node should exist

Error message

Custom Node should exist

What it means

resolve_network_node_type("Custom Node") resolves a network (structural) node type from the registry by display-name string (document_node_definitions.rs returns Option<&DocumentNodeDefinition>) and the .expect panics when no entry has exactly that name. This code runs during encapsulation — grouping the selected nodes into a newly inserted Custom Node and wiring imports/exports — so a missing or renamed entry aborts the operation mid-message, after DocumentMessage::AddTransaction was already queued.

Source

Thrown at editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs:668

						// The output gets connected to all the previous inputs the node was connected to
						let mut connect_output_to = Vec::new();
						for downstream_connection in downstream_connections {
							if downstream_connection.node_id().is_some_and(|downstream_node_id| selected_node_ids.contains(&downstream_node_id)) {
								continue;
							}
							connect_output_to.push(downstream_connection);
						}
						if !connect_output_to.is_empty() {
							// Every output connected to some non selected node forms a new export
							export_connections.push(current_output_connector);
							output_connections.push(connect_output_to);
						}
					}
				}

				// Use the network interface to add a default node, then set the imports, exports, paste the nodes inside, and connect them to the imports/exports
				let encapsulating_node_id = NodeId::new();
				let mut default_node_template = resolve_network_node_type("Custom Node").expect("Custom Node should exist").default_node_template();
				let Some(center_of_selected_nodes) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path).map(|[a, b]| (a + b) / 2.) else {
					log::error!("Could not get center of selected_nodes");
					return;
				};
				let center_of_selected_nodes_grid_space = IVec2::new((center_of_selected_nodes.x / 24. + 0.5).floor() as i32, (center_of_selected_nodes.y / 24. + 0.5).floor() as i32);
				default_node_template.node_type_metadata = NodeTypePersistentMetadata::node(center_of_selected_nodes_grid_space - IVec2::new(3, 1));
				responses.add(DocumentMessage::AddTransaction);
				responses.add(NodeGraphMessage::InsertNode {
					node_id: encapsulating_node_id,
					node_template: Box::new(default_node_template),
				});
				responses.add(NodeGraphMessage::SetDisplayNameImpl {
					node_id: encapsulating_node_id,
					network_path: selection_network_path.to_vec(),
					alias: "Untitled Node".to_string(),
				});

				responses.add(DocumentMessage::EnterNestedNetwork { node_id: encapsulating_node_id });

View on GitHub (pinned to c507b35645)

Solutions

  1. Check the network node registration list and confirm an entry with display name exactly 'Custom Node' exists and matches this literal byte-for-byte.
  2. Replace the string lookup with a stable identifier/constant so display-name renames cannot silently break resolution.
  3. Degrade the call site: let Some(template) = resolve_network_node_type("Custom Node") else { log::error!(..); return; } before queuing AddTransaction.
  4. Add a startup assertion that every string-resolved network type referenced by the editor actually resolves.

Example fix

// before
let mut default_node_template = resolve_network_node_type("Custom Node").expect("Custom Node should exist").default_node_template();

// after
let Some(mut default_node_template) = resolve_network_node_type("Custom Node").map(|node_type| node_type.default_node_template()) else {
	log::error!("Custom Node network type not registered");
	return;
};
Defensive patterns

Strategy: validation

Validate before calling

fn can_encapsulate_selection() -> bool {
	resolve_network_node_type("Custom Node").is_some()
}
// gate the 'group into node' menu action on this before dispatching the message

Type guard

fn network_type_available(name: &str) -> bool {
	resolve_network_node_type(name).is_some()
}

Prevention

When it happens

Trigger: Selecting nodes and invoking group-into-custom-node when the network node registry has no type whose display name is exactly 'Custom Node': the display name was renamed or localized, the registration list was edited in a fork, or the registry is not yet populated when the message is handled.

Common situations: Renaming the Custom Node's display name without updating this string literal; localization changing the effective lookup key; forks that drop custom-node support but leave the menu action reachable.

Related errors


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