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
- Check the network node registration list and confirm an entry with display name exactly 'Custom Node' exists and matches this literal byte-for-byte.
- Replace the string lookup with a stable identifier/constant so display-name renames cannot silently break resolution.
- Degrade the call site: let Some(template) = resolve_network_node_type("Custom Node") else { log::error!(..); return; } before queuing AddTransaction.
- 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
- Prefer stable identifiers over display-name strings for registry lookups
- Add a startup check that every string-resolved network type used by the editor exists
- When renaming a node's display name, grep for its string literal in lookups first
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.