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

  1. Verify `"Merge"` is a key in `DOCUMENT_NODE_TYPES` (search document_node_definitions.rs); restore the entry if missing.
  2. If the node was renamed, keep a `"Merge"` alias entry or update every `resolve_network_node_type("Merge")` call site to the new key.
  3. Replace `expect("Merge node")` with `Option` handling that logs and aborts layer creation gracefully.
  4. 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

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


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