{"record":{"id":"97216f2e0bb3e1d6","repo":"GraphiteEditor/Graphite","slug":"spline-node-does-not-exist","errorCode":null,"errorMessage":"Spline node does not exist","messagePattern":"Spline node does not exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"editor/src/messages/tool/tool_messages/spline_tool.rs","lineNumber":406,"sourceCode":"\n\t\t\t\t// Create new path in the selected layer when shift is down\n\t\t\t\tif let (Some(layer), true) = (selected_layer, append_to_selected_layer) {\n\t\t\t\t\ttool_data.current_layer = Some(layer);\n\n\t\t\t\t\tlet transform = document.metadata().transform_to_viewport(layer);\n\t\t\t\t\tlet position = transform.inverse().transform_point2(input.mouse.position);\n\t\t\t\t\ttool_data.next_point = position;\n\n\t\t\t\t\treturn SplineToolFsmState::Drawing;\n\t\t\t\t}\n\n\t\t\t\tresponses.add(DocumentMessage::DeselectAllLayers);\n\n\t\t\t\tlet parent = document.new_layer_bounding_artboard(input, viewport);\n\n\t\t\t\tlet path_node_type = resolve_network_node_type(\"Path\").expect(\"Path node does not exist\");\n\t\t\t\tlet path_node = path_node_type.default_node_template();\n\t\t\t\tlet spline_node_type = resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER).expect(\"Spline node does not exist\");\n\t\t\t\tlet spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]);\n\t\t\t\tlet nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)];\n\n\t\t\t\tlet layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses);\n\t\t\t\ttool_options.drawing.fill.apply_fill(layer, responses);\n\t\t\t\ttool_options.drawing.apply_stroke_to_new_layer(layer, responses);\n\t\t\t\ttool_options.drawing.apply_stroke_order_to_new_layer(layer, responses);\n\t\t\t\ttool_data.current_layer = Some(layer);\n\t\t\t\ttool_data.new_layer_viewport_start = Some(viewport_vec);\n\n\t\t\t\t// Position the layer at the initial mouse position via Transform\n\t\t\t\tresponses.add(DeferMessage::AfterGraphRun {\n\t\t\t\t\tmessages: vec![translation_transform_set(document, layer, viewport_vec), NodeGraphMessage::RunDocumentGraph.into()],\n\t\t\t\t});\n\n\t\t\t\tSplineToolFsmState::Drawing\n\t\t\t}\n\t\t\t(SplineToolFsmState::Drawing, SplineToolMessage::DragStop) => {","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/tool/tool_messages/spline_tool.rs#L388-L424","documentation":"The spline tool's second node is the Spline proto node (graphene_std::vector::spline::IDENTIFIER), resolved via resolve_proto_node_type and expected to exist in the DOCUMENT_NODE_TYPES registry. This expect guards that the spline vector manipulation node compiled into graphene_std was registered under the same identifier the editor searches for. It fires together with the Path lookup when the spline tool first builds its layer graph, so a panic here means registry/build drift for the proto node specifically.","triggerScenarios":"First spline click in a document: resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER).expect(\"Spline node does not exist\") runs immediately after the Path lookup, then node_template_input_override wires the spline node's input to the Path node (NodeId(1), output 0).","commonSituations":"Renaming or moving the spline node's IDENTIFIER in graphene_std::vector without updating spline_tool.rs; dropping the spline node registration during vector-node refactors; cargo features excluding the spline implementation; stale mixed builds after moving node definitions between crates.","solutions":["Compare graphene_std::vector::spline::IDENTIFIER with the registry keys (print collect_node_types()) to spot rename drift.","Always reference the IDENTIFIER constant from the defining crate instead of a string literal so renames propagate at compile time.","If the spline node was deliberately removed, disable the spline tool entry when the lookup returns None rather than expecting.","cargo clean and rebuild after cross-crate node moves so the registration macros regenerate."],"exampleFix":"// before\nlet spline_node_type = resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER).expect(\"Spline node does not exist\");\n\n// after\nlet Some(spline_node_type) = resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER) else {\n\tlog::error!(\"Spline proto node not registered; spline tool unavailable\");\n\treturn SplineToolFsmState::Ready;\n};","handlingStrategy":"validation","validationCode":"fn spline_node_registered() -> bool {\n\tresolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER).is_some()\n}\n\n// before the first spline click:\nif spline_node_registered() { /* create the spline layer */ } else { /* disable tool */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reference proto node identifiers via their crate constants; never inline identifier strings in tool code.","Rebuild fully after moving node definitions between crates so registry registration macros regenerate.","Include spline tool usage in post-registry-refactor smoke tests."],"tags":["rust","graphite-editor","node-registry","expect-panic","spline-tool","proto-node"],"backgroundTag":"static-registry-lookup-failed","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}