{"record":{"id":"0da324b6fa11dec0","repo":"GraphiteEditor/Graphite","slug":"failed-to-create-spline-node","errorCode":null,"errorMessage":"Failed to create Spline node","messagePattern":"Failed to create Spline node","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"editor/src/messages/tool/common_functionality/graph_modification_utils.rs","lineNumber":135,"sourceCode":"\t// Add a path node after the combine paths node\n\tlet path_node_id = NodeId::new();\n\tlet path_node = document_node_definitions::resolve_network_node_type(\"Path\")\n\t\t.expect(\"Failed to create path node\")\n\t\t.default_node_template();\n\tresponses.add(NodeGraphMessage::InsertNode {\n\t\tnode_id: path_node_id,\n\t\tnode_template: Box::new(path_node),\n\t});\n\tresponses.add(NodeGraphMessage::MoveNodeToChainStart {\n\t\tnode_id: path_node_id,\n\t\tparent: first_layer,\n\t});\n\n\t// Add a Spline node after the Path node if both the layers we are merging is spline.\n\tif current_and_other_layer_is_spline {\n\t\tlet spline_node_id = NodeId::new();\n\t\tlet spline_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER)\n\t\t\t.expect(\"Failed to create Spline node\")\n\t\t\t.default_node_template();\n\t\tresponses.add(NodeGraphMessage::InsertNode {\n\t\t\tnode_id: spline_node_id,\n\t\t\tnode_template: Box::new(spline_node),\n\t\t});\n\t\tresponses.add(NodeGraphMessage::MoveNodeToChainStart {\n\t\t\tnode_id: spline_node_id,\n\t\t\tparent: first_layer,\n\t\t});\n\t}\n\n\t// Add a transform node to ensure correct tooling modifications\n\tlet transform_node_id = NodeId::new();\n\tlet transform_node = document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)\n\t\t.expect(\"Failed to create transform node\")\n\t\t.default_node_template();\n\tresponses.add(NodeGraphMessage::InsertNode {\n\t\tnode_id: transform_node_id,","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/tool/common_functionality/graph_modification_utils.rs#L117-L153","documentation":"Graphite resolves node blueprints through a process-wide static registry: DOCUMENT_NODE_TYPES, a Lazy<HashMap<DefinitionIdentifier, DocumentNodeDefinition>> built by document_node_definitions() (document_node_definitions.rs:130). resolve_proto_node_type() (document_node_definitions.rs:1480) returns None when the ProtoNodeIdentifier is not a key in that map, and this .expect() in the layer-merge helper (graph_modification_utils.rs:134-136) turns that None into a panic while building the Spline node. It signals a code/registration mismatch, not bad user data.","triggerScenarios":"Invoking the merge flow with current_and_other_layer_is_spline == true (e.g. the Pen tool merging two spline-based layers) when graphene_std::vector::spline::IDENTIFIER has no matching entry in DOCUMENT_NODE_TYPES: the const was renamed, the Spline proto node was deleted or relocated, or the registration list was edited without re-adding it.","commonSituations":"Refactors that rename or move a node implementation without updating every tool-side IDENTIFIER reference; Graphite version upgrades where a proto node became a network node; cargo feature changes that conditionally register vector nodes; copy-paste of a sibling merge branch with a stale identifier.","solutions":["Grep the identifier's string value (e.g. \"Spline\") in document_node_definitions.rs and confirm a registration entry exists whose key exactly equals graphene_std::vector::spline::IDENTIFIER","If the node was renamed or moved, update the IDENTIFIER constant or the registration key so both sides agree, then rebuild","Replace .expect with let-else plus logging (and skip the spline insert) so a missing definition degrades instead of panicking the tool","Add a test that resolves every tool-referenced IDENTIFIER (Spline, Transform, Combine Paths, Path) against DOCUMENT_NODE_TYPES, mirroring the existing registry test at document_node_definitions.rs:1559"],"exampleFix":"// before\nlet spline_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER)\n\t.expect(\"Failed to create Spline node\")\n\t.default_node_template();\n// after\nlet Some(spline_node) = document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER) else {\n\tlog::error!(\"Spline node missing from DOCUMENT_NODE_TYPES; skipping spline merge step\");\n\treturn;\n};\nlet spline_node = spline_node.default_node_template();","handlingStrategy":"validation","validationCode":"// Verify registry membership before the merge flow, not mid-merge:\nfn can_merge_spline_layers() -> bool {\n\tdocument_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER).is_some()\n\t\t&& document_node_definitions::resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER).is_some()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat IDENTIFIER constants as the single source of truth; never inline string copies of node names at call sites","Grep for the identifier string across the repo before renaming or removing any proto node","Add a unit test resolving every tool-referenced identifier (Spline, Transform, Combine Paths, Path) against DOCUMENT_NODE_TYPES","Remember node_template_input_override indexes template.inputs directly — keep override arrays length-aligned with the node's inputs"],"tags":["rust","graphite","panic","expect","node-registry","layer-merge","spline"],"backgroundTag":"node-definition-not-found","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}