GraphiteEditor/Graphite · critical
Merge node
Error message
Merge node
What it means
Panics when `resolve_network_node_type("Merge")` returns `None` — a string-keyed lookup of the network node type `"Merge"` in the static `DOCUMENT_NODE_TYPES` registry (document_node_definitions.rs:1476-1478). `create_layer` inserts a Merge node as every new layer's chain head, so the `"Merge"` definition is a hard build-time dependency of layer creation. The expect asserts the registry contains that exact string key.
Source
Thrown at editor/src/messages/portfolio/document/graph_operation/utility_types.rs:66
responses,
layer_node: None,
import: false,
}
}
pub fn new_with_layer(layer: LayerNodeIdentifier, network_interface: &'a mut NodeNetworkInterface, responses: &'a mut VecDeque<Message>) -> Option<Self> {
if layer == LayerNodeIdentifier::ROOT_PARENT {
log::error!("LayerNodeIdentifier::ROOT_PARENT should not be used in ModifyInputsContext::new_with_layer");
return None;
}
let mut document = Self::new(network_interface, responses);
document.layer_node = Some(layer);
Some(document)
}
/// Creates a new layer and adds it to the document network. network_interface.move_layer_to_stack should be called after
pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier {
let new_merge_node = resolve_network_node_type("Merge").expect("Merge node").default_node_template();
self.network_interface.insert_node(new_id, new_merge_node, &[]);
LayerNodeIdentifier::new(new_id, self.network_interface)
}
/// Creates an artboard as the primary export for the document network.
pub fn create_artboard(&mut self, new_id: NodeId, location: DVec2, dimensions: DVec2, background: Color, clip: bool) -> LayerNodeIdentifier {
let artboard_node_template = resolve_network_node_type("Artboard").expect("Node").node_template_input_override([
Some(NodeInput::type_default(list!(Artboard), true)),
Some(NodeInput::type_default(list!(Graphic), true)),
Some(NodeInput::value(TaggedValue::DVec2(location), false)),
Some(NodeInput::value(TaggedValue::DVec2(dimensions), false)),
Some(NodeInput::value(TaggedValue::Color(background), false)),
Some(NodeInput::value(TaggedValue::Bool(clip), false)),
]);
self.network_interface.insert_node(new_id, artboard_node_template, &[]);
LayerNodeIdentifier::new(new_id, self.network_interface)
}
View on GitHub (pinned to c507b35645)
Solutions
- Verify `"Merge"` is a key in `DOCUMENT_NODE_TYPES` (search document_node_definitions.rs); restore the entry if missing.
- If the node was renamed, keep a `"Merge"` alias entry or update every `resolve_network_node_type("Merge")` call site to the new key.
- Replace `expect("Merge node")` with `Option` handling that logs and aborts layer creation gracefully.
- Add a startup/CI assertion that all string identifiers used by `ModifyInputsContext` resolve.
Example fix
// before
let new_merge_node = resolve_network_node_type("Merge").expect("Merge node").default_node_template();
// after
let Some(merge_def) = resolve_network_node_type("Merge") else {
log::error!("Merge node definition missing from registry; cannot create layer");
return layer; // or propagate an error to the caller
};
let new_merge_node = merge_def.default_node_template(); Defensive patterns
Strategy: validation
Validate before calling
// Before any layer creation flow, verify the Merge definition:
if document_node_definitions::resolve_network_node_type("Merge").is_none() {
log::error!("Merge node definition missing; layer creation disabled");
return;
} Type guard
fn merge_node_available() -> bool {
document_node_definitions::resolve_network_node_type("Merge").is_some()
} Try / catch
// Rust has no try/catch; degrade gracefully instead:
let Some(merge_def) = resolve_network_node_type("Merge") else {
log::error!("Merge definition missing; cannot create layer");
return;
}; Prevention
- Add a CI test asserting resolve_network_node_type resolves every string literal used in utility_types.rs
- Replace magic strings with shared constants defined next to the registry entries
- Never rename registry keys without adding an alias entry
- Since create_layer underpins nearly every tool, prioritize it in registry-change smoke tests
When it happens
Trigger: Any operation that creates a layer (`create_layer` from dozens of tool/insert handlers — pen tool, shape insertion, paste, etc.). The panic only fires if the `"Merge"` key is absent from `DOCUMENT_NODE_TYPES` — renamed display name, key typo in a refactor, or the definition entry was removed/feature-gated.
Common situations: Renaming the Merge node's registry key or display identifier; reorganizing the node registry macro and dropping the entry; string-lookup drift after a merge/rebase of the definitions file.
Related errors
- Node
- Blend node does not exist
- Origins to Polyline node does not exist
- Path node does not exist
- Solidify Stroke node should exist
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/55712f9477276c3b.
Report an issue: GitHub.