{"record":{"id":"55712f9477276c3b","repo":"GraphiteEditor/Graphite","slug":"merge-node","errorCode":null,"errorMessage":"Merge node","messagePattern":"Merge node","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"editor/src/messages/portfolio/document/graph_operation/utility_types.rs","lineNumber":66,"sourceCode":"\t\t\tresponses,\n\t\t\tlayer_node: None,\n\t\t\timport: false,\n\t\t}\n\t}\n\n\tpub fn new_with_layer(layer: LayerNodeIdentifier, network_interface: &'a mut NodeNetworkInterface, responses: &'a mut VecDeque<Message>) -> Option<Self> {\n\t\tif layer == LayerNodeIdentifier::ROOT_PARENT {\n\t\t\tlog::error!(\"LayerNodeIdentifier::ROOT_PARENT should not be used in ModifyInputsContext::new_with_layer\");\n\t\t\treturn None;\n\t\t}\n\t\tlet mut document = Self::new(network_interface, responses);\n\t\tdocument.layer_node = Some(layer);\n\t\tSome(document)\n\t}\n\n\t/// Creates a new layer and adds it to the document network. network_interface.move_layer_to_stack should be called after\n\tpub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier {\n\t\tlet new_merge_node = resolve_network_node_type(\"Merge\").expect(\"Merge node\").default_node_template();\n\t\tself.network_interface.insert_node(new_id, new_merge_node, &[]);\n\t\tLayerNodeIdentifier::new(new_id, self.network_interface)\n\t}\n\n\t/// Creates an artboard as the primary export for the document network.\n\tpub fn create_artboard(&mut self, new_id: NodeId, location: DVec2, dimensions: DVec2, background: Color, clip: bool) -> LayerNodeIdentifier {\n\t\tlet artboard_node_template = resolve_network_node_type(\"Artboard\").expect(\"Node\").node_template_input_override([\n\t\t\tSome(NodeInput::type_default(list!(Artboard), true)),\n\t\t\tSome(NodeInput::type_default(list!(Graphic), true)),\n\t\t\tSome(NodeInput::value(TaggedValue::DVec2(location), false)),\n\t\t\tSome(NodeInput::value(TaggedValue::DVec2(dimensions), false)),\n\t\t\tSome(NodeInput::value(TaggedValue::Color(background), false)),\n\t\t\tSome(NodeInput::value(TaggedValue::Bool(clip), false)),\n\t\t]);\n\t\tself.network_interface.insert_node(new_id, artboard_node_template, &[]);\n\t\tLayerNodeIdentifier::new(new_id, self.network_interface)\n\t}\n","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/graph_operation/utility_types.rs#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet new_merge_node = resolve_network_node_type(\"Merge\").expect(\"Merge node\").default_node_template();\n\n// after\nlet Some(merge_def) = resolve_network_node_type(\"Merge\") else {\n    log::error!(\"Merge node definition missing from registry; cannot create layer\");\n    return layer; // or propagate an error to the caller\n};\nlet new_merge_node = merge_def.default_node_template();","handlingStrategy":"validation","validationCode":"// Before any layer creation flow, verify the Merge definition:\nif document_node_definitions::resolve_network_node_type(\"Merge\").is_none() {\n    log::error!(\"Merge node definition missing; layer creation disabled\");\n    return;\n}","typeGuard":"fn merge_node_available() -> bool {\n    document_node_definitions::resolve_network_node_type(\"Merge\").is_some()\n}","tryCatchPattern":"// Rust has no try/catch; degrade gracefully instead:\nlet Some(merge_def) = resolve_network_node_type(\"Merge\") else {\n    log::error!(\"Merge definition missing; cannot create layer\");\n    return;\n};","preventionTips":["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"],"tags":["rust","panic","expect","node-registry","string-lookup","merge-node","layer-creation","graphite"],"backgroundTag":"node-definition-not-found","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}